/*
Cross Platform Core Code.

Copyright(R) 2012-2015 Sumscope Software.
All rights reserved.

Using:
class	CBondInfoArray;
class	CBondContainer;
class	CDomain;
class	CDomainContainer;

线程安全:
        除一下几个接口,都是线程安全的,所有非线程安全的函数开头有//NEED*的注释,搜索即可
        GetBondInfoByKeyEx
        GetAdditionBondInfo
        ElementAt
        GetBond
        IsHyHasPrice
        GetMaturityRangeEx
const参数:
        除了UpdateContainer接口的condStr,其他的所有BLHCONDITION参数都改为const引用

const成员函数:

大循环
        所有带有大循环的for语句右侧都增加了//BIGLOOP注释
        对于大循环锁,需要以下四个参数:
                开始拿锁的时间
                拿到锁的时间
                释放锁的时间
                代码的名称
                释放锁的时候,其他所有等待此锁的线程的名称,和等待时间
        而且,使用一个宏开关,就可以移除这些功能



*/
#define NOMINMAX
#include "BondContainer.h"

#include <core/container/LevelList.h>
#include <core/container/SHash.h>
#include <core/system/system_util.h>
#include <core/time/time.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>

#include <QDateTime>
#include <algorithm>
#include <mutex>

#include "ABSBondInfo.h"
#include "AdditionBondInfo.h"
#include "BondAuctionInfo.h"
#include "BondCDCPriceInfo.h"
#include "BondOptionInfo.h"
#include "BondSpecialLabel.h"
#include "MarketMakeTarget.h"
#include "SSCompanyReportManager.h"
#include "SSVContainer.h"
#include "SectorBond.h"
#include "qbprotocol/include/SSFilters.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
// #define new DEBUG_NEW
#endif

#define USE_BOND(OBJ, INDEX)
//////////////////////////////////////////////////////////////////////
#include "BondCSIPriceInfo.h"
#include "BondCalendar.h"
#include "QBBondCrmClause.h"
#include "QBIssuerInfo.h"
#include "QBProviceInfo.h"
// class CBondContainer

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

const int g_nMaxSize = 204800;
const int g_nMaxAddiSize = 8192;
const int g_nMaxOptionInfoSize = 16384;   // 16K
const int g_nMaxAuctionInfoSize = 16384;  // 16K

const char CBondContainer::lmCIB[] = "CIB";
const char CBondContainer::lmSSE[] = "SSE";
const char CBondContainer::lmSZE[] = "SZE";
const char CBondContainer::lmBSE[] = "BSE";

namespace {
// #define SSBONDNET_LOG
#ifdef SSBONDNET_LOG
#define NETLOG(format, ...) LOGWRITE(kLogLevelDebug, format, ##__VA_ARGS__)
#else
#define NETLOG(format, ...)
#endif
inline bool IsEmpty(const char* str) {
  return (str == nullptr || *str == '\0');
}

bool IsInToday(CBondContainer* pBondContainer, const char* args_time) {
  if (pBondContainer == nullptr || args_time == nullptr || IsEmpty(args_time))
    return false;

  time_t tSeverTime = ServerTimeMgr::instance().serverTime();
  tm stTm = qb::base::time2tm(tSeverTime);

  char strTime[12] = {0};
  strftime(strTime, 12, "%Y%m%d", &stTm);
  if (strcmp(strTime, args_time) == 0) return true;

  return true;
}

bool IsSplitBondInfoEnable() {
  static bool init = false;
  static bool enable = false;
  if (!init) {
    enable = false;  // boolTEST(kProfileSplitBondInfo);
    init = true;
  }
  return enable;
}

enum kTypeCategory {
  kTypeCategoryCoupon = 0,  //
  kTypeCategoryProd = 1,    //
  kTypeCategoryRating = 2,  //
  kTypeCategoryInst = 3,    //
  kTypeCategoryMax = 4,     //
  kTypeCategoryCDCRating = 5,
  kTypeCategoryCSIRating = 6,
  kTypeCategoryCBRRating = 7,
};
class TypeNameManager {
  CSPString m_coupon_names[CBondContainer::CouponMax + 1];
  CSPString m_prod_names[CBondContainer::ProdMax + 1];
  CSPString m_rating_names[CBondContainer::RatingMax + 1];
  CSPString m_inst_names[CBondContainer::InstMax + 1];
  CSPString m_cdcrating_names[CBondContainer::CDCRatingMax + 1];
  CSPString m_csirating_names[CBondContainer::CSIRatingMax + 1];
  CSPString m_cbrrating_names[CBondContainer::CBRRatingMax + 1];
  CSPString m_blank;
  bool m_initialized;
  std::mutex m_lock;

 public:
  static TypeNameManager& Get() {
    static TypeNameManager tnm;
    return tnm;
  }
  TypeNameManager() : m_initialized(false) {}
  ~TypeNameManager() {}
  bool IsRatingEqual(CBondContainer::IssuerRating filter, const char* ratting) {
    Prepare();
    if (filter == CBondContainer::RatingAll)
      return true;
    else if (filter == CBondContainer::RatingNone)
      return false;
    else if (filter == CBondContainer::RatingOther) {
      if (IsEmpty(ratting)) return true;
      if (ratting) {
        if (strcmp(ratting, "CCL") == 0) return true;
        if (strcmp(m_rating_names[CBondContainer::RatingAAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_rating_names[CBondContainer::RatingAAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_rating_names[CBondContainer::RatingAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_rating_names[CBondContainer::RatingAA].c_str(), ratting) ==
                0 ||
            strcmp(m_rating_names[CBondContainer::RatingAAN].c_str(),
                   ratting) == 0 ||
            strcmp(m_rating_names[CBondContainer::RatingAP].c_str(), ratting) ==
                0)
          return false;
      }
      return true;
    } else if (filter > CBondContainer::RatingAll &&
               filter < CBondContainer::RatingOther) {
      return ratting && strcmp(m_rating_names[filter].c_str(), ratting) == 0;
    }
    return false;
  }

  bool IsCDCRatingEqual(CBondContainer::CDCRating filter, const char* ratting) {
    Prepare();
    if (filter == CBondContainer::CDCRatingAll)
      return true;
    else if (filter == CBondContainer::CDCRatingNone)
      return false;
    else if (filter == CBondContainer::CDCRatingOther) {
      if (IsEmpty(ratting)) return true;
      if (ratting) {
        if (strcmp(m_cdcrating_names[CBondContainer::CDCRatingAAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAAAM].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAA2].c_str(),
                   ratting) == 0 ||
            strcmp(m_cdcrating_names[CBondContainer::CDCRatingAAM].c_str(),
                   ratting) == 0)
          return false;
      }
      return true;
    } else if (filter > CBondContainer::CDCRatingAll &&
               filter < CBondContainer::CDCRatingOther) {
      bool bRet =
          (ratting && strcmp(m_cdcrating_names[filter].c_str(), ratting) == 0);
      return bRet;
    }
    return false;
  }

  bool IsCSIRatingEqual(CBondContainer::CSIRating filter, const char* ratting) {
    Prepare();
    if (filter == CBondContainer::CSIRatingAll)
      return true;
    else if (filter == CBondContainer::CSIRatingNone)
      return false;
    else if (filter == CBondContainer::CSIRatingOther) {
      if (IsEmpty(ratting)) return true;
      if (ratting) {
        if (strcmp(m_csirating_names[CBondContainer::CSIRatingAAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_csirating_names[CBondContainer::CSIRatingAAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_csirating_names[CBondContainer::CSIRatingAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_csirating_names[CBondContainer::CSIRatingAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_csirating_names[CBondContainer::CSIRatingAA2].c_str(),
                   ratting) == 0 ||
            strcmp(m_csirating_names[CBondContainer::CSIRatingAAM].c_str(),
                   ratting) == 0)
          return false;
      }
      return true;
    } else if (filter > CBondContainer::CSIRatingAll &&
               filter < CBondContainer::CSIRatingOther) {
      return ratting && strcmp(m_csirating_names[filter].c_str(), ratting) == 0;
    }
    return false;
  }

  bool IsCBRRatingEqual(CBondContainer::CBRRating filter, const char* ratting) {
    Prepare();
    if (filter == CBondContainer::CBRRatingAll)
      return true;
    else if (filter == CBondContainer::CBRRatingNone)
      return false;
    else if (filter == CBondContainer::CBRRatingOther) {
      if (IsEmpty(ratting)) return true;
      if (ratting) {
        if (strcmp(m_cbrrating_names[CBondContainer::CBRRatingAAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAAAM].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAAP].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAA].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAAM].c_str(),
                   ratting) == 0 ||
            strcmp(m_cbrrating_names[CBondContainer::CBRRatingAP].c_str(),
                   ratting) == 0)
          return false;
      }
      return true;
    } else if (filter > CBondContainer::CBRRatingAll &&
               filter < CBondContainer::CBRRatingOther) {
      return ratting && strcmp(m_cbrrating_names[filter].c_str(), ratting) == 0;
    }
    return false;
  }

  const CSPString& GetTypeName(kTypeCategory category, uint32_t nType) {
    Prepare();
    switch (category) {
      case kTypeCategoryCoupon:
        return m_coupon_names[nType];
        break;
      case kTypeCategoryProd:
        return m_prod_names[nType];
        break;
      case kTypeCategoryRating:
        return m_rating_names[nType];
        break;
      case kTypeCategoryInst:
        return m_inst_names[nType];
        break;
      case kTypeCategoryCDCRating:
        return m_cdcrating_names[nType];
        break;
      case kTypeCategoryCSIRating:
        return m_csirating_names[nType];
        break;
      case kTypeCategoryCBRRating:
        return m_cbrrating_names[nType];
        break;
      default:
        break;
    }
    return m_blank;
  }

 protected:
  inline void Prepare() {
    if (!m_initialized) {
      std::lock_guard<std::mutex> locker(m_lock);
      if (!m_initialized) {
        Init();
        m_initialized = true;
      }
    }
  }
  void Init() {
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponNon, "");
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponAll, "ALL");
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponSHIBOR, "SHIBOR");
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponDEPO, "DEPO");
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponLPR, "LPR");
    AddTypeName(kTypeCategoryCoupon, CBondContainer::CouponFIX, "FIXED");

    AddTypeName(kTypeCategoryInst, CBondContainer::InstNone, "");
    AddTypeName(kTypeCategoryInst, CBondContainer::InstAll, "ALL");
    AddTypeName(kTypeCategoryInst, CBondContainer::InstCentr, "CGE");
    AddTypeName(kTypeCategoryInst, CBondContainer::InstConty, "LGE");
    AddTypeName(kTypeCategoryInst, CBondContainer::InstPrvat, "PVE");
    AddTypeName(kTypeCategoryInst, CBondContainer::InstOther, "OTE");

    AddTypeName(kTypeCategoryRating, CBondContainer::RatingNone, "");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAll, "ALL");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAAAP, "AAA+");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAAA, "AAA");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAAP, "AA+");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAA, "AA");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAAN, "AA-");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingAP, "A+");
    AddTypeName(kTypeCategoryRating, CBondContainer::RatingOther, "");

    AddTypeName(kTypeCategoryProd, CBondContainer::ProdNone, "");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdAll, "全部");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdLocal, "地方债");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdCountry, "国债");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdCenter, "央票");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdFinance, "金融债");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdShort, "短融");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdChina, "中票");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdEnterpr, "企业债");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdPPN, "PPN");
    AddTypeName(kTypeCategoryProd, CBondContainer::ProdNCD, "NCD");

    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingNone, "");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAll, "ALL");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAAAP, "AAA+");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAAA, "AAA");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAAAM, "AAA-");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAAP, "AA+");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAA, "AA");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAA2, "AA(2)");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingAAM, "AA-");
    AddTypeName(kTypeCategoryCDCRating, CBondContainer::CDCRatingOther, "");

    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingNone, "");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAll, "ALL");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAAAP, "AAA+");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAAA, "AAA");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAAP, "AA+");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAA, "AA");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAA2, "AA2");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingAAM, "AA-");
    AddTypeName(kTypeCategoryCSIRating, CBondContainer::CSIRatingOther, "");

    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingNone, "");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAll, "ALL");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAAAP, "AAA+");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAAA, "AAA");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAAAM, "AAA-");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAAP, "AA+");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAA, "AA");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAAM, "AA-");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingAP, "A+");
    AddTypeName(kTypeCategoryCBRRating, CBondContainer::CBRRatingOther, "");
  }
  int GetCapcity(kTypeCategory category) const {
    switch (category) {
      case kTypeCategoryCoupon:
        return CBondContainer::CouponMax + 1;
        break;
      case kTypeCategoryProd:
        return CBondContainer::ProdMax + 1;
        break;
      case kTypeCategoryRating:
        return CBondContainer::RatingMax + 1;
        break;
      case kTypeCategoryInst:
        return CBondContainer::InstMax + 1;
        break;
      case kTypeCategoryCDCRating:
        return CBondContainer::CDCRatingMax + 1;
        break;
      case kTypeCategoryCSIRating:
        return CBondContainer::CSIRatingMax + 1;
        break;
      case kTypeCategoryCBRRating:
        return CBondContainer::CBRRatingMax + 1;
        break;
        break;
    }
    return 0;
  }
  void AddTypeName(kTypeCategory category, uint32_t nType, const char* name) {
    switch (category) {
      case kTypeCategoryCoupon:
        m_coupon_names[nType] = name;
        break;
      case kTypeCategoryProd:
        m_prod_names[nType] = name;
        break;
      case kTypeCategoryRating:
        m_rating_names[nType] = name;
        break;
      case kTypeCategoryInst:
        m_inst_names[nType] = name;
        break;
      case kTypeCategoryCDCRating:
        m_cdcrating_names[nType] = name;
        break;
      case kTypeCategoryCSIRating:
        m_csirating_names[nType] = name;
        break;
      case kTypeCategoryCBRRating:
        m_cbrrating_names[nType] = name;
        break;
      default:
        break;
    }
  }
};

/*
大循环
所有带有大循环的for语句右侧都增加了//BIGLOOP注释
对于大循环锁,需要以下四个参数:
开始拿锁的时间
拿到锁的时间
释放锁的时间
代码的名称
释放锁的时候,其他所有等待此锁的线程的名称,和等待时间
而且,使用一个宏开关,就可以移除这些功能
可重入
*/
}  // namespace
////////////////////////////////////////////////////////////////////////////////
namespace {
class ScopedMutex {
 public:
  enum kLockType { kLockTypeRead, kLockTypeWrite, kLockTypeHuge };

 protected:
  std::recursive_mutex& m_lock;
  kLockType m_type;
  uint64_t m_time_start;
  uint64_t m_time_get;
  const char* m_file;
  int m_line;

 public:
  ScopedMutex(std::recursive_mutex& lock, kLockType type = kLockTypeRead)
      : m_lock(lock), m_type(type) {
    m_lock.lock();
  }
  ScopedMutex(std::recursive_mutex& lock, const char* file, int line)
      : m_lock(lock), m_file(file), m_line(line), m_type(kLockTypeHuge) {
    if (m_type == kLockTypeHuge) m_time_start = qb::base::HighResTime();
    m_lock.lock();
    if (m_type == kLockTypeHuge) m_time_get = qb::base::HighResTime();
  }
  ~ScopedMutex() {
    m_lock.unlock();
    if (m_type == kLockTypeHuge) {
      uint64_t curtime = qb::base::HighResTime();
      log_info("[HUGELOCK]time:%8d-%8d  file:%s-%d",
               (unsigned int)(m_time_get - m_time_start),
               (unsigned int)(curtime - m_time_get),
               qb::base::StringUtil::GetShortFileName(m_file, 1), m_line);
    }
  }
};

#define HUGELOCK(LOCK) ScopedMutex _scoped_(LOCK, __FILE__, __LINE__);
#define READLOCK(LOCK) ScopedMutex _scoped_(LOCK, ScopedMutex::kLockTypeRead);
#define WRITELOCK(LOCK) ScopedMutex _scoped_(LOCK, ScopedMutex::kLockTypeWrite);
}  // namespace

void _SplitStr(std::vector<std::string>& dst, const std::string& src,
               const std::string& seps) {
  dst.clear();

  size_t last = 0;
  size_t index = 0;
  int kLen = seps.length();
  index = src.find(seps, 0);
  while (index != std::string::npos) {
    if (index - last > 0) {
      dst.push_back(src.substr(last, index - last));
    }

    last = index + kLen;
    index = src.find(seps, last);
  }

  if (src.length() > last) {
    dst.push_back(src.substr(last));
  }
}

BrokerKey::BrokerKey() : m_nIndex(0), m_brokid(""){};

BrokerKey::BrokerKey(const char* szid, int nIndex)
    : m_nIndex(nIndex), m_brokid(szid) {}
BrokerKey::BrokerKey(BrokerKey&& broker)
    : m_brokid(std::move(broker.m_brokid)), m_nIndex(broker.m_nIndex) {}
BrokerKey::BrokerKey(const BrokerKey& broker)
    : m_brokid(broker.m_brokid), m_nIndex(broker.m_nIndex) {}
BrokerKey& BrokerKey::operator=(BrokerKey&& broker) {
  std::swap(m_brokid, broker.m_brokid);
  std::swap(m_nIndex, broker.m_nIndex);
  return *this;
}

BrokerKey& BrokerKey::operator=(const BrokerKey& broker) {
  m_brokid = broker.m_brokid;
  m_nIndex = broker.m_nIndex;
  return *this;
}

BrokerKey::BrokerKey(const std::string& szid, int nIndex)
    : m_nIndex(nIndex),
      m_brokid(szid){

      };
unsigned int BrokerKey::GetHash() const {
  unsigned int hash = m_nIndex;
  hash += m_brokid.size() > 0
              ? (qb::base::GetFastHash(m_brokid.c_str(), m_brokid.size(), 0))
              : 0;
  return hash;
}
bool BrokerKey::operator==(const BrokerKey& key) const {
  return m_nIndex == key.m_nIndex && m_brokid == key.m_brokid;
}
const bool BrokerKey::operator<(const BrokerKey& obj) const {
  if (m_brokid < obj.m_brokid)
    return true;
  else if (m_brokid == obj.m_brokid && m_nIndex < obj.m_nIndex) {
    return true;
  } else
    return false;
}
void BrokerKey::Clear() {
  m_nIndex = 0;
  m_brokid = "";  // 0 对应""
}
void BrokerKey::SetBrokerId(const std::string& brokerIdStr) {
  m_brokid = brokerIdStr;
}
void BrokerKey::SetBrokerId(const char* brokerIdStr) { m_brokid = brokerIdStr; }
const std::string& BrokerKey::GetBrokerId() const { return m_brokid; }
////////////////////////////////////////////////////////////////////////////////

CBondContainer::CBondContainer()
    : m_map(StringPtrMap::kKeyModeAsCode),
      m_keymap(StringPtrMap::kKeyModeAsKey) {
  m_nMinIssueDate = -1;
  m_nMaxIssueDate = -1;
  m_pfnProgressProgram = 0;
  m_nLastReportDate = 0;
  m_nLastCalcDate = 0;
  ReserveSize(g_nMaxSize, g_nMaxAddiSize);
}

CBondContainer& CBondContainer::instance() {
  static CBondContainer s_container;
  return s_container;
}

CBondContainer::~CBondContainer() {
  // Clear( );
}
void CBondContainer::ReserveSize(int maxBondListSize, int maxAddSize) {
  HUGELOCK(m_mutex);
  // LOGINFO("m_vctbond size:%d capcity:%d,m_vctaddi size:%d capcity:%d",
  // m_vctbond.size(), m_vctbond.capacity(), m_vctaddi.size(),
  // m_vctaddi.capacity());

  m_vctbond.reserve(maxBondListSize);
  m_vctaddi.reserve(maxAddSize);
  m_vctoptioninfo.reserve(g_nMaxOptionInfoSize);
  m_vctauctioninfo.reserve(g_nMaxAuctionInfoSize);
  int hash_capcity = qb::base::GetHashPrimeLargerThan(maxBondListSize);
  m_map.InitHashTable(hash_capcity);
  m_keymap.InitHashTable(hash_capcity);
  // LOGINFO("reserve:%d,%d  size:%d capcity:%d,m_vctaddi size:%d capcity:%d",
  // maxBondListSize,maxAddSize,
  // m_vctbond.size(), m_vctbond.capacity(), m_vctaddi.size(),
  // m_vctaddi.capacity());
}
void CBondContainer::RebuildMap() {
  int nCapacity = 0;
  {
    HUGELOCK(m_mutex);
    nCapacity = m_vctbond.capacity();
    SetMap();
  }

  BrokerRepMng->Reserve(nCapacity);
  BankClientRepMng->Reserve(nCapacity);
  BankRepMng->Reserve(nCapacity);
  XCQuoteRepMng->Reserve(nCapacity);
  CfetsRepMng->Reserve(nCapacity);
  CfetsDealRepMng->Reserve(nCapacity);
}

bool CBondContainer::Lock() {
  m_mutex.lock();
  return true;
}

bool CBondContainer::UnLock() {
  m_mutex.unlock();
  return true;
}

int CBondContainer::Add(CBondInfo& newElement, CAdditionBondInfo* pAddi,
                        CBondCompanyRep* pCompanyRep, CBondBankRep* pBankRep,
                        CXCQuoteRep* pXCQuote, CCFETSQuoteRep* pCFETSQuote) {
  return Add(new CBondInfo(newElement), pAddi, pCompanyRep, pBankRep, pXCQuote,
             pCFETSQuote);
}

int CBondContainer::Add(CBondInfo* pNewElement,
                        CAdditionBondInfo* pAddi /*=nullptr*/,
                        CBondCompanyRep* pCompanyRep, CBondBankRep* pBankRep,
                        CXCQuoteRep* pXCQuote, CCFETSQuoteRep* pCFETSQuote) {
  // 使得外部来创建CBondInfo
  WRITELOCK(m_mutex);
  int capcity = m_vctbond.capacity();
  m_vctbond.push_back(pNewElement);
  if (m_vctbond.capacity() != capcity) {
    // BLOGCRIT("[BONDS]m_vctbond changed capcity from %d to %d", capcity,
    // m_vctbond.capacity());
  }
  int nIndex = m_vctbond.size() - 1;
  AddAdditionInfo(nIndex, pAddi);
  m_map.SetAt(pNewElement->GetCombBondCode(), (void*)(intptr_t)nIndex);
  m_keymap.SetAt(pNewElement->GetCombBondKey(), (void*)(intptr_t)nIndex);
  return nIndex;
}
int CBondContainer::AddAdditionInfo(int nBondIndex,
                                    CAdditionBondInfo* pAddInfo) {
  WRITELOCK(m_mutex);
  if (nBondIndex < 0 || nBondIndex >= (int)m_vctbond.size() ||
      nullptr == pAddInfo)
    return -1;
  int capcity = m_vctaddi.capacity();
  m_vctaddi.push_back(new CAdditionBondInfo(*pAddInfo));
  if (m_vctaddi.capacity() != capcity) {
    // BLOGCRIT("[BONDS]m_vctaddi changed capcity from %d to
    // %d",capcity,m_vctaddi.capacity());
  }
  int nAddiIndex = m_vctaddi.size() - 1;

  CBondInfo* pinfo = m_vctbond[nBondIndex];
  if (pinfo) {
    pinfo->SetAdditionInfoIndex(nAddiIndex);
  }

  int nFirstIndex = GetBondIndexImpl(pAddInfo->GetFirstIssueKey(), -1);
  m_mapaddi[nFirstIndex].insert(nBondIndex);

  return nBondIndex;
}

int CBondContainer::AddBondOptionInfo(CBondOptionInfo* pOpi) {
  WRITELOCK(m_mutex);
  if (nullptr == pOpi) return -1;

  int capcity = m_vctoptioninfo.capacity();
  m_vctoptioninfo.push_back(new CBondOptionInfo(*pOpi));
  if (m_vctoptioninfo.capacity() != capcity) {
    // BLOGCRIT("[BONDS]m_vctoptioninfo changed capcity from %d to %d", capcity,
    // m_vctoptioninfo.capacity());
  }
  int nIndex = m_vctoptioninfo.size() - 1;
  int bondIndex = GetBondIndex(pOpi->GetCombBondKey());
  if (!IsValidIndex(bondIndex)) return nIndex;

  CBondInfo* pinfo = m_vctbond[bondIndex];
  if (pinfo) {
    pinfo->SetOptionInfoIndex(nIndex);
  }

  return nIndex;
}

void CBondContainer::RemoveBondOptionInfo(CBondOptionInfo* pOpi) {
  WRITELOCK(m_mutex);
  if (nullptr == pOpi) return;

  int bondIndex = GetBondIndex(pOpi->GetCombBondKey());
  if (!IsValidIndex(bondIndex)) return;

  CBondInfo* pinfo = m_vctbond[bondIndex];
  if (!pinfo) return;

  int nIndex = pinfo->GetOptionInfoIndex();
  if (nIndex < 0 || nIndex >= (int)m_vctoptioninfo.size()) return;
  CBondOptionInfo* opi = m_vctoptioninfo[nIndex];
  if (!opi) return;
  if (strcmp(opi->GetCombBondKey(), pinfo->GetCombBondKey()) != 0) return;
  delete opi;
  m_vctoptioninfo[nIndex] = nullptr;
  return;
}

const CBondOptionInfo* CBondContainer::GetBondOptionInfo(int index) const {
  if (index < 0 || index >= (int)m_vctoptioninfo.size()) return nullptr;

  return m_vctoptioninfo[index];
}

int CBondContainer::AddBondAuctionInfo(int nBondIndex, CBondAuctionInfo* pAuc) {
  WRITELOCK(m_mutex);
  if (nBondIndex < -1 || nBondIndex >= (int)m_vctbond.size() || nullptr == pAuc)
    return -1;

  if (nBondIndex == -1) {  // Auction字典比Bond字典早更新的情况
    static CBondInfo biEmpty;
    biEmpty.Clear();
    biEmpty.SetListedMarket(pAuc->GetBondKey());
    biEmpty.SetBondKey(pAuc->GetBondKey());
    nBondIndex = Add(biEmpty, nullptr);
  }

  int capcity = m_vctauctioninfo.capacity();
  m_vctauctioninfo.push_back(new CBondAuctionInfo(*pAuc));
  if (m_vctauctioninfo.capacity() != capcity) {
    // BLOGCRIT("[BONDS]m_vctauctioninfo changed capcity from %d to %d",
    // capcity, m_vctauctioninfo.capacity());
  }
  int nIndex = m_vctauctioninfo.size() - 1;

  m_mapauctioninfo[nBondIndex] = nIndex;
  return nBondIndex;
}

void CBondContainer::RemoveBondAuctionInfo(int nBondIndex) {
  WRITELOCK(m_mutex);
  auto it = m_mapauctioninfo.find(nBondIndex);
  if (it == m_mapauctioninfo.end()) return;

  int nIndex = it->second;
  if (nIndex < 0 || nIndex >= (int)m_vctauctioninfo.size()) return;
  CBondAuctionInfo* opi = m_vctauctioninfo[nIndex];
  if (!opi) return;
  delete opi;
  m_vctauctioninfo[nIndex] = nullptr;
  return;
}

const CBondAuctionInfo* CBondContainer::GetBondAuctionInfo(int nBondIndex) {
  auto it = m_mapauctioninfo.find(nBondIndex);
  if (it == m_mapauctioninfo.end()) return nullptr;
  return m_vctauctioninfo[it->second];
}

int CBondContainer::AddABSBondInfo(int nBondIndex, CABSBondInfo* pInfo) {
  ////WRITELOCK(m_mutex);
  if (nBondIndex < 0 || nBondIndex >= (int)m_vctbond.size() || nullptr == pInfo)
    return -1;

  int capcity = m_vctabsbond.capacity();
  m_vctabsbond.push_back(new CABSBondInfo(*pInfo));
  if (m_vctabsbond.capacity() != capcity) {
    // BLOGCRIT("[BONDS]m_vctabsbond changed capcity from %d to %d", capcity,
    // m_vctabsbond.capacity());
  }
  int nIndex = m_vctabsbond.size() - 1;

  m_mapabsbond[nBondIndex] = nIndex;

  return nBondIndex;
}

const CABSBondInfo* CBondContainer::GetABSBondInfo(int nBondIndex) {
  auto it = m_mapabsbond.find(nBondIndex);
  if (it == m_mapabsbond.end()) return nullptr;
  return m_vctabsbond[it->second];
}

int CBondContainer::GetMatchType(const char* pstr) {
  int nRet = -1;
  char* pt = (char*)pstr;
  char nChar = pt[0];
  while (nChar != '\0') {
    if (nChar >= '0' && nChar <= '9') {
      if (nRet > 0 && nRet != 1) {
        nRet = 3;
        break;
      }
      nRet = 1;
    } else if (nChar >= 'A' && nChar <= 'Z') {
      if (nRet > 0 && nRet != 2) {
        nRet = 3;
        break;
      }
      nRet = 2;
    } else {
      nRet = 3;
      break;
    }
    pt++;
    nChar = pt[0];
  }

  return nRet;
}

bool CBondContainer::GetBondClntPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  BKQUOTE quote = {0};
  if (instance().GetClentInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    if (pRep->m_Freeze == 1) return false;

    if (strcmp(pRep->m_BidStatus, "1") != 0 &&
        strcmp(pRep->m_OfrStatus, "1") != 0)
      return false;  // 双边无报价
    if (atof(pRep->m_BidVol) == 0.0 && atof(pRep->m_OfrVol) == 0.0)
      return false;  // 双边量为0

    // 价、量只要一边为0即表示无交，如果两边都不效则不显示
    if ((atof(pRep->m_Bid) <= 0.0000 || atof(pRep->m_BidVol) <= 0.0000) &&
        (atof(pRep->m_Ofr) <= 0.0000 || atof(pRep->m_OfrVol) <= 0.0000)) {
      return false;
    }

    return ((!IsEmpty(pRep->m_Bid) && strcmp(pRep->m_BidStatus, "1") == 0) ||
            (!IsEmpty(pRep->m_Ofr) &&
             strcmp(pRep->m_OfrStatus, "1") == 0));  // 有效报价
  }
  return false;
}

bool CBondContainer::IsHasPrice(const BLHCONDITION& Cond, int nID,
                                PriceValid flag) {
  if (IsEmpty(Cond.sCompanyid))  // 经纪公司ID，银行ID
  {
    if (nID < 0 || nID >= GetSize()) return false;
    CBondCompanyRep* ptmp = GetCompanyRep(nID);
    if (ptmp && ptmp->GetSize() > 0) return ptmp->IsHasPrice("", flag);
    return false;
  }
  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp) return ptmp->IsHasPrice(Cond.sCompanyid, flag);
  return false;
}

bool CBondContainer::GetCFETSBidCndPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  if (IsEmpty(Cond.sBPrice) && IsEmpty(Cond.sBPriceEnd)) return true;

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (rep) {
    CFETSQUOTE quote;
    if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                            quote))
      return false;

    if (!IsEmpty(quote.m_BidPriceYield)) {
      float fBid = atof(quote.m_BidPriceYield);

      bool bRet = false;
      if (!IsEmpty(Cond.sBPrice) && !IsEmpty(Cond.sBPriceEnd)) {
        bRet = (fBid > (atof(Cond.sBPrice) - 0.00001));
        if (bRet) bRet = (fBid < (atof(Cond.sBPriceEnd) + 0.00001));
      } else {
        if (!IsEmpty(Cond.sBPrice))
          bRet = (fBid > (atof(Cond.sBPrice) - 0.00001));

        if (!bRet && !IsEmpty(Cond.sBPriceEnd))
          bRet = (fBid < (atof(Cond.sBPriceEnd) + 0.00001));
      }

      return bRet;
    }
  }

  return false;
}

bool CBondContainer::GetCFETSOfrCndPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  if (IsEmpty(Cond.sOPrice) && IsEmpty(Cond.sOPriceEnd)) return true;

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (rep) {
    CFETSQUOTE quote;
    if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                            quote))
      return false;

    if (!IsEmpty(quote.m_OfrPriceYield)) {
      float fOfr = atof(quote.m_OfrPriceYield);

      bool bRet = false;
      if (!IsEmpty(Cond.sOPrice) && !IsEmpty(Cond.sOPriceEnd)) {
        bRet = (fOfr > (atof(Cond.sOPrice) - 0.00001));
        if (bRet) bRet = (fOfr < (atof(Cond.sOPriceEnd) + 0.00001));
      } else {
        if (!IsEmpty(Cond.sOPrice))
          bRet = (fOfr > (atof(Cond.sOPrice) - 0.00001));

        if (!bRet && !IsEmpty(Cond.sOPriceEnd))
          bRet = (fOfr < (atof(Cond.sOPriceEnd) + 0.00001));
      }

      return bRet;
    }
  }

  return false;
}

bool CBondContainer::GetCFETSBidCdcCompare(const BLHCONDITION& Cond, int nID,
                                           bool bIsCDCAuthValid) {
  if (Cond.sBidCdc[0] == '\0' && Cond.sBidCdcEnd[0] == '\0') return true;

  CCFETSQuoteRep* rep = CBondContainer::instance().GetCFETSQuote(nID);
  if (!rep) return false;

  CFETSQUOTE quote;
  if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                          quote))
    return false;

  if (quote.m_BidPriceYield[0] == '\0' ||
      strcmp(quote.m_BidPriceYield, "0") == 0)
    return false;

  double dDiff = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
      bIsCDCAuthValid, nID, CBondCDCPriceInfo::price_type_yield, true,
      quote.m_BidPriceYield, INVALID_CDC_VALUE, false);
  if (dDiff < INVALID_CDC_VALUE + 1e-6) return false;
  if (Cond.sBidCdc[0] != 0) {
    if (dDiff < atof(Cond.sBidCdc) - 1e-6) return false;
  }
  if (Cond.sBidCdcEnd[0] != 0) {
    if (dDiff > atof(Cond.sBidCdcEnd) + 1e-6) return false;
  }
  return true;
}

bool CBondContainer::GetCFETSCdcOfrCompare(const BLHCONDITION& Cond, int nID,
                                           bool bIsCDCAuthValid) {
  if (Cond.sCdcOfr[0] == '\0' && Cond.sCdcOfrEnd[0] == '\0') return true;

  CCFETSQuoteRep* rep = CBondContainer::instance().GetCFETSQuote(nID);
  if (!rep) return false;

  CFETSQUOTE quote;
  if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                          quote))
    return false;

  if (quote.m_OfrPriceYield[0] == '\0' ||
      strcmp(quote.m_OfrPriceYield, "0") == 0)
    return false;
  double dDiff = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
      bIsCDCAuthValid, nID, CBondCDCPriceInfo::price_type_yield, false,
      quote.m_OfrPriceYield, INVALID_CDC_VALUE, false);
  if (dDiff < INVALID_CDC_VALUE + 1e-6) return false;
  if (Cond.sCdcOfr[0] != 0) {
    if (dDiff < atof(Cond.sCdcOfr) - 1e-6) return false;
  }
  if (Cond.sCdcOfrEnd[0] != 0) {
    if (dDiff > atof(Cond.sCdcOfrEnd) + 1e-6) return false;
  }
  return true;
}

bool CBondContainer::GetCFETSDiffPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;
  float fDiffprc = atof(Cond.sDiffPrice);

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (rep) {
    CFETSQUOTE quote;
    if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                            quote))
      return false;
    if (!IsEmpty(quote.m_BidPriceYield)) {
      return fDiffprc >=
             (atof(quote.m_BidPriceYield) - atof(quote.m_OfrPriceYield)) *
                 100.00;
    }
  }

  return false;
}

bool CBondContainer::GetCFETSBidVol(const BLHCONDITION& Cond, int nID) {
  if (!IsValidIndex(nID)) return false;
  if (IsEmpty(Cond.sVolBid)) return true;

  double fFilterVol = atof(Cond.sVolBid);

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (rep) {
    CFETSQUOTE quote;
    if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                            quote))
      return false;
    if (IsEmpty(quote.m_BidVol)) return false;
    double fVolumn = atof(quote.m_BidVol);
    if (Cond.nVolBpcCnd == 0 &&
        fVolumn < fFilterVol + 0.000001)  // 0 表示[<= ], 1 表示[>= ]
    {
      return true;
    } else if (Cond.nVolBpcCnd == 1 && fVolumn > fFilterVol - 0.000001) {
      return true;
    }
  }

  return false;
}

bool CBondContainer::GetCFETSOfrVol(const BLHCONDITION& Cond, int nID) {
  if (!IsValidIndex(nID)) return false;
  if (IsEmpty(Cond.sVolOfr)) return true;

  double fFilterVol = atof(Cond.sVolOfr);

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (rep) {
    CFETSQUOTE quote;
    if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                            quote))
      return false;
    if (IsEmpty(quote.m_OfrVol)) return false;
    double fVolumn = atof(quote.m_OfrVol);
    if (Cond.nVolOpcCnd == 0 &&
        fVolumn < fFilterVol + 0.000001)  // 0 表示[<= ], 1 表示[>= ]
    {
      return true;
    } else if (Cond.nVolOpcCnd == 1 && fVolumn > fFilterVol - 0.000001) {
      return true;
    }
  }

  return false;
}

bool CBondContainer::IsCFETSBilateralPrice(const BLHCONDITION& Cond,
                                           int nID) {  // CFETS双边报价检查
  if (strcmp(Cond.sCompanyid, "50") != 0) return false;

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (!rep) return false;
  CFETSQUOTE quote;
  if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                          quote))
    return false;
  return ((!IsEmpty(quote.m_BidPriceYield) || !IsEmpty(quote.m_BidPriceClean) ||
           !IsEmpty(quote.m_BidVol)) &&
          (!IsEmpty(quote.m_OfrPriceYield) || !IsEmpty(quote.m_OfrPriceClean) ||
           !IsEmpty(quote.m_OfrVol)));

  return true;
}

bool CBondContainer::IsCFETSHasPrice(const BLHCONDITION& Cond, int nID) {
  if (strcmp(Cond.sCompanyid, "50") != 0) return false;

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (!rep) return false;
  CFETSQUOTE quote;
  if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                          quote))
    return false;
  return (!IsEmpty(quote.m_BidPriceYield) || !IsEmpty(quote.m_BidPriceClean) ||
          !IsEmpty(quote.m_BidVol) || !IsEmpty(quote.m_OfrPriceYield) ||
          !IsEmpty(quote.m_OfrPriceClean) || !IsEmpty(quote.m_OfrVol));

  return false;
}

bool CBondContainer::CheckCFETSSettlement(const BLHCONDITION& Cond, int nID) {
  if (strcmp(Cond.sCompanyid, "50") != 0) return false;

  CCFETSQuoteRep* rep = instance().GetCFETSQuote(nID);
  if (!rep) return false;
  CFETSQUOTE quote;
  if (!rep->GetQuoteByKey((CCFETSQuote::CFETSQUOTETYPE)Cond.nCFETSQuoteType,
                          quote))
    return false;
  return FilterQuoteByClearSpeed(quote, Cond.nSettlement[0] - 1);

  return true;
}

bool CBondContainer::IsCpicHasPrice(const BLHCONDITION& Cond, int nID,
                                    bool bBuyPool) {
  return GetCpicCompanyInfoById(nID, bBuyPool);
}

bool CBondContainer::GetMaturityBond(const CBondInfo& Info) {
  if (IsEmpty(Info.GetMaturityDate())) return false;
  time_t t = ServerTimeMgr::instance().serverTime();
  Info.GetRemainPeriod(t);
  if (strcmp(Info.GetRemainDate(), strBondLib_Expired() /*"已到期"*/) != 0)
    return false;
  return true;
}

bool CBondContainer::GetRebateBond(const CBondInfo& Info) {
  if (Info.IsRebated()) return false;
  return true;
}

bool CBondContainer::GetProdMultiType(const BLHCONDITION& Cond,
                                      const CBondInfo& Info) {
  for (int i = 0; i < BLH_BONDTYPECOUNT; i++) {
    if (Cond.nTypeNew[i] == CBondContainer::newBondNone) return false;
    const CSPString& strProdType = GetProdType(Cond.nTypeNew[i]);
    if (strcmp(strProdType.c_str(), Info.GetBondSubType()) == 0)
      return true;
    else
      continue;
  }
  return true;
}

bool CBondContainer::GetSOEenterType(const BLHCONDITION& Cond,
                                     const CBondInfo& Info) {
  int nSize = sizeof(Cond.nTypeNew) / sizeof(uint32_t);

  for (int i = 0; i < nSize; i++) {
    if (Cond.nTypeNew[i] == 0x00) return false;
    if (Cond.nTypeNew[i] == typeAll) {
      CSPString strProdType = Info.GetBondSubType();
      if (!Info.IsSOEenterType() &&
          (strcmp(strProdType.c_str(), GetProdType(ProdShort).c_str()) == 0 ||
           strcmp(strProdType.c_str(), GetProdType(ProdChina).c_str()) == 0 ||
           strcmp(strProdType.c_str(), GetProdType(ProdEnterpr).c_str()) == 0 ||
           strcmp(strProdType.c_str(), GetProdType(ProdPPN).c_str()) == 0)) {
        return false;
      }
      return true;
    } else if (Cond.nTypeNew[i] == ProdShort || Cond.nTypeNew[i] == ProdChina ||
               Cond.nTypeNew[i] == ProdEnterpr || Cond.nTypeNew[i] == ProdPPN) {
      CSPString strProdType = GetProdType(Cond.nTypeNew[i]);
      if (Info.IsSOEenterType() &&
          strcmp(strProdType.c_str(), Info.GetBondSubType()) == 0)
        return true;
      else
        continue;
    } else {
      CSPString strProdType = GetProdType(Cond.nTypeNew[i]);
      if (strcmp(strProdType.c_str(), Info.GetBondSubType()) == 0)
        return true;
      else
        continue;
    }
  }

  return true;
}

bool CBondContainer::GetMultiLevel(const BLHCONDITION& Cond,
                                   const CBondInfo& Info) {
  // 非ALL情况下对指定债券的主体评级与过滤器值进行对比
  //
  CBondContainer::IssuerRating filter = CBondContainer::RatingNone;
  int nSize = sizeof(Cond.nIssuerRating) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nIssuerRating[i] == 0x00) return false;
    filter = (CBondContainer::IssuerRating)Cond.nIssuerRating[i];
    if (filter == CBondContainer::RatingOther) {
      if (strcmp(Info.GetBondSubType(), "PSB") == 0) return false;

      if (TypeNameManager::Get().IsRatingEqual(filter,
                                               Info.GetIssuerRating()) &&
          TypeNameManager::Get().IsRatingEqual(filter,
                                               Info.GetInstitutionRating()))
        return true;
    } else {
      if (TypeNameManager::Get().IsRatingEqual(filter, Info.GetIssuerRating()))
        return true;
      if (TypeNameManager::Get().IsRatingEqual(filter,
                                               Info.GetInstitutionRating()))
        return true;
    }
  }
  return false;
}

bool CBondContainer::GetCDCRatingLevel(const BLHCONDITION& Cond,
                                       const CBondInfo& Info) {
  if (!SSUserAccountManager::instance().HasAuthOfCDC()) return true;

  CBondContainer::CDCRating filter = CBondContainer::CDCRatingNone;
  int nSize = sizeof(Cond.nCDCRating) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nCDCRating[i] == 0x00) return false;
    filter = (CBondContainer::CDCRating)Cond.nCDCRating[i];
    if (TypeNameManager::Get().IsCDCRatingEqual(filter, Info.GetCDCRating()))
      return true;
  }

  return false;
}

bool CBondContainer::GetCSIRatingLevel(const BLHCONDITION& Cond,
                                       const CBondInfo& Info) {
  if (!SSUserAccountManager::instance().HasAuthOfCSI()) return true;

  {
    CBondContainer::CSIRating filter = CBondContainer::CSIRatingNone;
    int nSize = sizeof(Cond.nCSIRating) / sizeof(uint32_t);
    for (int i = 0; i < nSize; i++) {
      if (Cond.nCSIRating[i] == 0x00) return false;
      filter = (CBondContainer::CSIRating)Cond.nCSIRating[i];
      if (TypeNameManager::Get().IsCSIRatingEqual(filter, Info.GetCSIRating()))
        return true;
    }
  }

  return false;
}

bool CBondContainer::GetCBRRatingLevel(const BLHCONDITION& Cond,
                                       const CBondInfo& Info) {
  if (!SSUserAccountManager::instance().HasAuthOfCBR()) return true;

  {
    CBondContainer::CBRRating filter = CBondContainer::CBRRatingNone;
    int nSize = sizeof(Cond.nCBRRating) / sizeof(uint32_t);
    for (int i = 0; i < nSize; i++) {
      if (Cond.nCBRRating[i] == 0x00) return false;
      filter = (CBondContainer::CBRRating)Cond.nCBRRating[i];
      if (TypeNameManager::Get().IsCBRRatingEqual(filter, Info.GetCBRRating()))
        return true;
    }
  }

  return false;
}

bool CBondContainer::GetOutlookRatingLevel(const BLHCONDITION& Cond,
                                           const CBondInfo& Info) {
  CBondContainer::OutlookRating filter = OutlookRatingNone;
  int nSize = sizeof(Cond.nOutlookRating) / sizeof(uint32_t);
  for (int i = 0; i < nSize; ++i) {
    if (Cond.nOutlookRating[i] == OutlookRatingNone) return false;
    filter = (CBondContainer::OutlookRating)Cond.nOutlookRating[i];
    CBondContainer::OutlookRating nBondOutlookRating = OutlookRatingNone;
    if (strcmp(Info.GetOutlook(), "STB") == 0) {
      nBondOutlookRating = CBondContainer::OutlookRatingSTB;
    } else if (strcmp(Info.GetOutlook(), "NEG") == 0) {
      nBondOutlookRating = CBondContainer::OutlookRatingNEG;
    } else if (strcmp(Info.GetOutlook(), "RWT") == 0) {
      nBondOutlookRating = CBondContainer::OutlookRatingRWT;
    } else if (strcmp(Info.GetOutlook(), "POS") == 0) {
      nBondOutlookRating = CBondContainer::OutlookRatingPOS;
    }

    if (nBondOutlookRating == filter) return true;
  }

  return false;
}

bool CBondContainer::GetBondBkPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  if (Cond.nBkClnt != 0) return GetBondClntPrice(Cond, nID);

  BKQUOTE quote = {0};
  if (instance().GetBankInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    if (strcmp(pRep->m_BidStatus, "1") != 0 &&
        strcmp(pRep->m_OfrStatus, "1") != 0)
      return false;  // 双边无报价
    return ((!IsEmpty(pRep->m_Bid) && strcmp(pRep->m_BidStatus, "1") == 0) ||
            (!IsEmpty(pRep->m_Ofr) &&
             strcmp(pRep->m_OfrStatus, "1") == 0));  // 有效报价
  }
  return false;
}

bool CBondContainer::GetBondBkdbPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  if (Cond.nBkClnt != 0) return GetBondClntdbPrice(Cond, nID);

  BKQUOTE quote = {0};
  if (instance().GetBankInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    return ((!IsEmpty(pRep->m_Bid) && strcmp(pRep->m_BidStatus, "1") == 0) &&
            (!IsEmpty(pRep->m_Ofr) &&
             strcmp(pRep->m_OfrStatus, "1") == 0));  // 双边有效报价
  }
  return false;
}

bool CBondContainer::GetMultiCouponType(const BLHCONDITION& Cond,
                                        const CBondInfo& Info) {
  int nSize = sizeof(Cond.nCouponType) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nCouponType[i] == CouponNon) return false;
    CSPString strSpec = GetCouponType(Cond.nCouponType[i]);
    if (strcmp(strSpec.c_str(), Info.GetRateType()) == 0) return true;
  }
  return true;
}

bool CBondContainer::GetMultiInstion(const BLHCONDITION& Cond,
                                     const CBondInfo& Info) {
  int nSize = sizeof(Cond.nInstion) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nInstion[i] == 0x00) return false;
    CSPString strInst = GetInstType(Cond.nInstion[i]);
    if (strcmp(strInst.c_str(), Info.GetInstitutionType()) == 0)
      return true;
    else
      continue;
  }
  return true;
}

long CBondContainer::GetDateRange(const CBondInfo& Info) {
  if (IsEmpty(Info.GetMaturityDate())) return 0;

  long lDate = atol(Info.GetMaturityDate());
  int nYear, nMonth, nDay;
  nYear = lDate / 10000;
  nMonth = (lDate % 10000) / 100;
  nDay = lDate % 100;

  QDateTime tmMaturiy = QDate(nYear, nMonth, nDay).startOfDay();
  QDateTime tmNow = QDateTime::fromSecsSinceEpoch(
      ServerTimeMgr::instance().serverTime());  // TODO utc?
  return tmNow.daysTo(tmMaturiy);
}

bool CBondContainer::GetDiffPrice(const BLHCONDITION& Cond, int nID) {
  if (IsEmpty(Cond.sCompanyid)) {
    if (nID < 0 || nID >= instance().GetSize()) return true;

    CBondCompanyRep* ptmp = instance().GetCompanyRep(nID);
    if (ptmp && ptmp->GetSize() > 0)
      return instance().GetDiffenceById(Cond, nID);

    return true;
  }
  float fDiffprc = atof(Cond.sDiffPrice);
  if (Cond.nBnkFlg != 0) {
    if (Cond.nBkClnt != 0) {
      BKQUOTE quote = {0};
      if (instance().GetClentInfoById(Cond.sCompanyid, nID, quote)) {
        BKQUOTE* pRep = &quote;
        if (strcmp(pRep->m_BidStatus, "1") != 0 ||
            strcmp(pRep->m_OfrStatus, "1") != 0)
          return false;

        if (IsEmpty(pRep->m_Bid) || IsEmpty(pRep->m_Ofr))
          return false;  // 单边无报价

        return fDiffprc >= (atof(pRep->m_Bid) - atof(pRep->m_Ofr)) * 100.00;
      }
      return false;
    } else {
      BKQUOTE quote = {0};
      if (instance().GetBankInfoById(Cond.sCompanyid, nID, quote)) {
        BKQUOTE* pRep = &quote;
        if (strcmp(pRep->m_BidStatus, "1") != 0 ||
            strcmp(pRep->m_OfrStatus, "1") != 0)
          return false;

        if (IsEmpty(pRep->m_Bid) || IsEmpty(pRep->m_Ofr))
          return false;  // 单边无报价

        return fDiffprc >= (atof(pRep->m_Bid) - atof(pRep->m_Ofr)) * 100.00;
      }
      return false;
    }
  } else {
    REPORT quote = {0};
    if (instance().GetCompanyInfoById(Cond.sCompanyid, nID, quote)) {
      REPORT* pRep = &quote;
      if (strcmp(pRep->m_bidinfo.m_sPrice, "Bid") == 0 ||
          strcmp(pRep->m_askinfo.m_sPrice, "Ofr") == 0)
        return false;

      return fDiffprc >=
             (atof(pRep->m_bidinfo.m_sPrice) - atof(pRep->m_askinfo.m_sPrice)) *
                 100.00;
    }
    return false;
  }
  return false;
}

bool CBondContainer::CheckBidPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= GetSize()) return false;

  if (Cond.sBPrice[0] == '\0' && Cond.sBPriceEnd[0] == '\0') return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->TestBidPrice(Cond)) return true;

  return false;
}

bool CBondContainer::CheckOfrPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= GetSize()) return false;

  if (Cond.sOPrice[0] == '\0' && Cond.sOPriceEnd[0] == '\0') return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->TestOfrPrice(Cond)) return true;
  return false;
}

bool CBondContainer::CheckBidOfrPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= GetSize()) return false;

  if (Cond.sBidOfr[0] == '\0' && Cond.sBidOfrEnd[0] == '\0') return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->TestBidOfrPrice(Cond)) return true;
  return false;
}

bool CBondContainer::GetBondClntdbPrice(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  BKQUOTE quote = {0};
  if (instance().GetClentInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    if (strcmp(pRep->m_BidStatus, "1") != 0 ||
        strcmp(pRep->m_OfrStatus, "1") != 0)
      return false;  // 双边无报价
    return ((!IsEmpty(pRep->m_Bid) && strcmp(pRep->m_BidStatus, "1") == 0) &&
            (!IsEmpty(pRep->m_Ofr) &&
             strcmp(pRep->m_OfrStatus, "1") == 0));  // 有效报价
  }
  return false;
}

unsigned char CBondContainer::GetCFETSSpeedType(const std::string& sDes) {
  if (sDes.find("T+0") != sDes.npos) {
    return 0x1;
  } else if (sDes.find("T+1") != sDes.npos) {
    return 0x2;
  }
  return 0;
}

bool CBondContainer::GetCltOffsetEstPrc(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= instance().GetSize()) return false;

  BKQUOTE quote = {0};
  if (instance().GetClentInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    QDateTime sCurTm = QDateTime::currentDateTime();
    QDateTime sTime = QDateTime::fromSecsSinceEpoch(pRep->m_Time);
    if (pRep->m_Time > 0 && sTime.date().day() != sCurTm.date().day())
      return true;
  }

  return false;
}

bool CBondContainer::GetMaturityRange(const BLHCONDITION& Cond,
                                      const CBondInfo& Info,
                                      bool bSecondaryMarket) {
  int nSize = sizeof(Cond.nRange) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nRange[i]) {
      case RangeOther:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      case RangeDate:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      default:
        break;
    }
  }
  if (IsEmpty(Info.GetMaturityDate())) return false;

  LONG ldays = 0;
  time_t server_time = ServerTimeMgr::instance().serverTime();
  if (bSecondaryMarket) {
    time_t t = server_time;
    ldays = Info.GetRemainedDays(t);
  } else {
    std::string str = Info.GetMaturityTerm();
    if (str.length() > 0) {
      ldays = (LONG)CalcRemainingDay(str);
    } else
      return false;  // 字典缺失期限字段，认为筛选失败
  }

  LONG lDate = atol(Info.GetMaturityDate());
  uint32_t Today = CBondCalendar::TimeToInt(server_time);
  time_t T0 = CBondCalendar::IntToTime(Today);
  if ((Today % 10000) == 229) Today -= 1;

  bool bRes = false;

  for (int i = 0; i < nSize; i++) {
    if (Cond.nRange[i] == 0x00) return false;

    switch (Cond.nRange[i]) {
      case Range1:
        if (ldays <= 90)
          return true;
        else
          continue;
        break;
      case Range2:
        if (ldays >= 90 && ldays <= 180)
          return true;
        else
          continue;
        break;
      case Range3:
        if (ldays >= 180 && ldays <= 270)
          return true;
        else
          continue;
        break;
      case Range4: {
        time_t t1Y = CBondCalendar::IntToTime(Today + 10000);
        int d1Y = (t1Y - T0) / (60 * 60 * 24);
        if (ldays >= 270 && ldays <= d1Y)
          return true;
        else
          continue;
        break;
      }
      case Range5: {
        time_t t1Y = CBondCalendar::IntToTime(Today + 10000);
        int d1Y = (t1Y - T0) / (60 * 60 * 24);
        time_t t3Y = CBondCalendar::IntToTime(Today + 30000);
        int d3Y = (t3Y - T0) / (60 * 60 * 24);
        if (ldays >= d1Y && ldays <= d3Y)
          return true;
        else
          continue;
        break;
      }
      case Range6: {
        time_t t3Y = CBondCalendar::IntToTime(Today + 30000);
        int d3Y = (t3Y - T0) / (60 * 60 * 24);
        time_t t5Y = CBondCalendar::IntToTime(Today + 50000);
        int d5Y = (t5Y - T0) / (60 * 60 * 24);
        if (ldays >= d3Y && ldays <= d5Y)
          return true;
        else
          continue;
        break;
      }
      case Range7: {
        time_t t5Y = CBondCalendar::IntToTime(Today + 50000);
        int d5Y = (t5Y - T0) / (60 * 60 * 24);
        time_t t7Y = CBondCalendar::IntToTime(Today + 70000);
        int d7Y = (t7Y - T0) / (60 * 60 * 24);
        if (ldays >= d5Y && ldays <= d7Y)
          return true;
        else
          continue;
        break;
      }
      case Range8: {
        time_t t7Y = CBondCalendar::IntToTime(Today + 70000);
        int d7Y = (t7Y - T0) / (60 * 60 * 24);
        time_t t10Y = CBondCalendar::IntToTime(Today + 100000);
        int d10Y = (t10Y - T0) / (60 * 60 * 24);
        if (ldays >= d7Y && ldays <= d10Y)
          return true;
        else
          continue;
        break;
      }
      case Range9: {
        time_t t10Y = CBondCalendar::IntToTime(Today + 100000);
        int d10Y = (t10Y - T0) / (60 * 60 * 24);
        if (ldays >= d10Y)
          return true;
        else
          continue;
        break;
      }
      case RangeOther: {
        // scofined.qi:改进性能和bug
        // 修复只有"D","Y" 会数据检查通过的问题,
        // JIRA 10495:3.3回归 经济商现券 筛选:期限
        // D/Y模式在上限或者下限输入框任意输入D或者Y,都有剩余期限是0的结果返回
        bool useLeft = !IsEmpty(Cond.sDate1);
        bool useRight = !IsEmpty(Cond.sDate2);
        if (!useLeft && !useRight) return true;
        if (Info.IsRight()) ldays = Info.GetRemainedDays(server_time);

        float daysLeft = useLeft ? (atof(Cond.sDate1)) : 0.0f;
        float daysRight = useRight ? (atof(Cond.sDate2)) : 0.0f;
        if (useLeft &&
            !(strrchr(Cond.sDate1, 'D') || strrchr(Cond.sDate1, 'd')))
          daysLeft *= 365;
        if (daysRight &&
            !(strrchr(Cond.sDate2, 'D') || strrchr(Cond.sDate2, 'd')))
          daysRight *= 365;
        if (useLeft && !useRight) {
          if (ldays >= daysLeft) return true;
        }
        if (ldays >= daysLeft && ldays <= daysRight)
          return true;
        else
          continue;
      } break;
      case RangeDate: {
        // 旧代码中,将ldays与Cond.sDate1,Cond.sDate2做比较是不对的,格式不一样
        bool passed = true;
        if (passed && !IsEmpty(Cond.sDate1) && lDate < atol(Cond.sDate1))
          passed = false;
        if (passed && !IsEmpty(Cond.sDate2) && lDate > atol(Cond.sDate2))
          passed = false;
        if (passed)
          return true;
        else
          continue;
      } break;
      case RangeRealDate: {
        int nIndex = -1;
        int ldays1, ldays2 = 0;
        QString strDate1 = Cond.sDate1;
        QString strDate2 = Cond.sDate2;
        if (strDate1.length() <= 0 && strDate2.length() <= 0) return true;
        strDate1 = strDate1.toUpper();
        strDate2 = strDate2.toUpper();
        if (strDate1.indexOf("D") != -1) {
          strDate1.replace("D", "");
          ldays1 = strDate1.toInt();
        } else {
          strDate1.replace("Y", "");
          ldays1 = strDate1.toFloat() * 365;
        }
        if (strDate2.indexOf("D") != -1) {
          strDate2.replace("D", "");
          ldays2 = strDate2.toInt();
        } else {
          strDate2.replace("Y", "");
          ldays2 = strDate2.toFloat() * 365;
        }
        if (Info.IsRight()) {
          ldays = Info.GetRemainedDays(server_time);
        }
        if (strDate1.length() > 0 && strDate2.length() <= 0)
          if (ldays >= ldays1) return true;
        if (ldays >= ldays1 && ldays <= ldays2)
          return true;
        else
          continue;
      } break;
      case RangeMulDate: {
        time_t t = server_time;
        std::string str = Info.GetRemainPeriod(t);
        bool bRemain = false;
        if (str.size() > 0) {
          ldays = (long)CalcRemainingDay(str);
          if (ldays > 0) {
            bRemain = true;
          }
        }
        if (!bRemain) {
          if (!IsEmpty(Info.GetMaturityTerm())) {
            std::string str = Info.GetMaturityTerm();
            ldays = CBondContainer::CalcRemainingDay(str);
          } else
            ldays = 0;
        }

        int nIndex = -1;
        int ldays1, ldays2 = 0;
        QString strDate1 = Cond.sDate1;  // TODO: in UTF-8
        QString strDate2 = Cond.sDate2;
        if (strDate1.length() <= 0 && strDate2.length() <= 0) return true;
        strDate1 = strDate1.toUpper();
        strDate2 = strDate2.toUpper();
        if (strDate1.indexOf("D") != -1) {
          strDate1.replace("D", "");
          ldays1 = strDate1.toInt();
        } else {
          strDate1.replace("Y", "");
          ldays1 = strDate1.toFloat() * 365;
        }
        if (strDate2.indexOf("D") != -1) {
          strDate2.replace("D", "");
          ldays2 = strDate2.toInt();
        } else {
          strDate2.replace("Y", "");
          ldays2 = strDate2.toFloat() * 365;
        }
        if (Info.IsRight()) {
          ldays = Info.GetRemainedDays(server_time);
        }
        if (strDate1.length() > 0 && strDate2.length() <= 0)
          if (ldays >= ldays1) return true;
        if (ldays >= ldays1 && ldays <= ldays2)
          return true;
        else
          continue;
      } break;
      default:
        break;
    }

    if (!bRes) break;
  }
  return bRes;
}

bool CBondContainer::GetMaturityTermRange(const BLHCONDITION& Cond,
                                          const CBondInfo& Info,
                                          bool bSecondaryMarket) {
  int nSize = sizeof(Cond.nRange) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nRange[i]) {
      case RangeOther:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      case RangeDate:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      case RangeRealDate:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      case RangeMulDate:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      default:
        break;
    }
  }

  int ldays = 0;
  time_t server_time = ServerTimeMgr::instance().serverTime();
  if (bSecondaryMarket) {
    time_t t = server_time;
    std::string str = Info.GetRemainPeriod(t);
    ldays = (int)CalcRemainingDay(str);
  } else {
    std::string str = Info.GetMaturityTerm();
    if (str.length() > 0) {
      ldays = (int)CalcRemainingDay(str);
    } else
      return false;  // 字典缺失期限字段，认为筛选失败
  }

  int lDate = atol(Info.GetMaturityDate());
  bool bRes = false;

  for (int i = 0; i < nSize; i++) {
    if (Cond.nRange[i] == 0x00) return false;

    switch (Cond.nRange[i]) {
      case Range1:
        if (ldays <= 90)
          return true;
        else
          continue;
        break;
      case Range2:
        if (ldays >= 90 && ldays <= 180)
          return true;
        else
          continue;
        break;
      case Range3:
        if (ldays >= 180 && ldays <= 270)
          return true;
        else
          continue;
        break;
      case Range4:
        if (ldays >= 270 && ldays <= 365)
          return true;
        else
          continue;
        break;
      case Range5:
        if (ldays >= 365 && ldays <= 365 * 3)
          return true;
        else
          continue;
        break;
      case Range6:
        if (ldays >= 365 * 3 && ldays <= 365 * 5)
          return true;
        else
          continue;
        break;
      case Range7:
        if (ldays >= 365 * 5 && ldays <= 365 * 7)
          return true;
        else
          continue;
        break;
      case Range8:
        if (ldays >= 365 * 7 && ldays <= 365 * 10)
          return true;
        else
          continue;
        break;
      case Range9:
        if (ldays >= 365 * 10)
          return true;
        else
          continue;
        break;
      case RangeOther: {
        int nIndex = -1;
        int ldays1, ldays2 = 0;
        QString strDate1 = Cond.sDate1;
        QString strDate2 = Cond.sDate2;
        if (strDate1.length() <= 0 && strDate2.length() <= 0) return true;
        strDate1 = strDate1.toUpper();
        strDate2 = strDate2.toUpper();
        if (strDate1.indexOf("D") != -1) {
          strDate1.replace("D", "");
          ldays1 = strDate1.toInt();
        } else {
          strDate1.replace("Y", "");
          ldays1 = strDate1.toFloat() * 365;
        }
        if (strDate2.indexOf("D") != -1) {
          strDate2.replace("D", "");
          ldays2 = strDate2.toInt();
        } else {
          strDate2.replace("Y", "");
          ldays2 = strDate2.toFloat() * 365;
        }
        if (Info.IsRight()) {
          ldays = Info.GetRemainedDays(server_time);
        }

        if (strDate1.length() > 0 && strDate2.length() <= 0)
          if (ldays >= ldays1) return true;
        if (ldays >= ldays1 && ldays <= ldays2)
          return true;
        else
          continue;
      } break;
      case RangeDate: {
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        int ldays1 = atol(Cond.sDate1);
        int ldays2 = atol(Cond.sDate2);
        if (!IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2))
          if (ldays >= ldays1) return true;
        if (lDate >= ldays1 && lDate <= ldays2)
          return true;
        else
          continue;
      } break;
      case RangeRealDate: {
        int nIndex = -1;
        int ldays1, ldays2 = 0;
        QString strDate1 = Cond.sDate1;
        QString strDate2 = Cond.sDate2;
        if (strDate1.length() <= 0 && strDate2.length() <= 0) return true;
        strDate1 = strDate1.toUpper();
        strDate2 = strDate2.toUpper();
        if (strDate1.indexOf("D") != -1) {
          strDate1.replace("D", "");
          ldays1 = strDate1.toInt();
        } else {
          strDate1.replace("Y", "");
          ldays1 = strDate1.toFloat() * 365;
        }
        if (strDate2.indexOf("D") != -1) {
          strDate2.replace("D", "");
          ldays2 = strDate2.toInt();
        } else {
          strDate2.replace("Y", "");
          ldays2 = strDate2.toFloat() * 365;
        }
        if (Info.IsRight()) {
          ldays = Info.GetRemainedDays(server_time);
        }
        if (strDate1.length() > 0 && strDate2.length() <= 0)
          if (ldays >= ldays1) return true;
        if (ldays >= ldays1 && ldays <= ldays2)
          return true;
        else
          continue;
      } break;
      case RangeMulDate: {
        time_t t = server_time;
        std::string str = Info.GetRemainPeriod(t);
        bool bRemain = false;
        if (str.size() > 0) {
          ldays = (int)CalcRemainingDay(str);
          if (ldays > 0) {
            bRemain = true;
          }
        }
        if (!bRemain) {
          if (!IsEmpty(Info.GetMaturityTerm())) {
            std::string str = Info.GetMaturityTerm();
            ldays = CBondContainer::CalcRemainingDay(str);
          } else
            ldays = 0;
        }
        int nIndex = -1;
        int ldays1, ldays2 = 0;
        QString strDate1 = Cond.sDate1;
        QString strDate2 = Cond.sDate2;
        if (strDate1.length() <= 0 && strDate2.length() <= 0) return true;
        strDate1 = strDate1.toUpper();
        strDate2 = strDate2.toUpper();
        if (strDate1.indexOf("D") != -1) {
          strDate1.replace("D", "");
          ldays1 = strDate1.toInt();
        } else {
          strDate1.replace("Y", "");
          ldays1 = strDate1.toFloat() * 365;
        }
        if (strDate2.indexOf("D") != -1) {
          strDate2.replace("D", "");
          ldays2 = strDate2.toInt();
        } else {
          strDate2.replace("Y", "");
          ldays2 = strDate2.toFloat() * 365;
        }
        if (Info.IsRight()) {
          ldays = Info.GetRemainedDays(server_time);
        }
        if (strDate1.length() > 0 && strDate2.length() <= 0)
          if (ldays >= ldays1) return true;
        if (ldays >= ldays1 && ldays <= ldays2)
          return true;
        else
          continue;
      } break;
    }

    if (!bRes) break;
  }
  return bRes;
}

bool CBondContainer::GetDeadLineRange(const BLHCONDITION& Cond,
                                      const CBondInfo& Info) {
  bool bRes = false;
  int nSize = sizeof(Cond.nRange) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nRange[i]) {
      case DL_RangeDate:
        if (IsEmpty(Cond.sMTDate1) && IsEmpty(Cond.sMTDate2)) return true;
        break;
      default:
        break;
    }
  }
  if (IsEmpty(Info.GetMaturityTerm())) {
    // LOGWARN("MaturityTerm is empty");
    return false;
  }

  double lfStartDLYear = 0.0;
  double lfEndDLYear = 0.0;
  std::string strDeadLine(Info.GetMaturityTerm());
  if (strDeadLine.length() <= 0) return false;

  int nYFindIndex = strDeadLine.find('Y', 0);
  int nMFindIndex = strDeadLine.find('M', 0);
  int nDFindIndex = strDeadLine.find('D', 0);

  double fYear = 0.0;
  if (nYFindIndex >= 0) {
    strDeadLine.erase(nYFindIndex, 1);
    fYear = atof(strDeadLine.c_str());
  } else if (nMFindIndex >= 0) {
    strDeadLine.erase(nMFindIndex, 1);
    fYear = atof(strDeadLine.c_str()) / 12.0;
  } else if (nDFindIndex >= 0) {
    strDeadLine.erase(nDFindIndex, 1);
    fYear = atof(strDeadLine.c_str()) / 365.0;
  }

  // 判断条件：前开后闭
  for (int i = 0; i < nSize; i++) {
    if (Cond.nDeadLineRange[i] == 0x00) return false;

    switch (Cond.nDeadLineRange[i]) {
      case DL_Range1: {
        lfStartDLYear = (1 - 1) / 12.0;
        lfEndDLYear = (1 + 1) / 12.0;
      } break;
      case DL_Range2: {
        lfStartDLYear = (3 - 1) / 12.0;
        lfEndDLYear = (3 + 1) / 12.0;
      } break;
      case DL_Range3: {
        lfStartDLYear = (6 - 1) / 12.0;
        lfEndDLYear = (6 + 1) / 12.0;
      } break;
      case DL_Range4: {
        lfStartDLYear = (9 - 2) / 12.0;
        lfEndDLYear = (9 + 2) / 12.0;
      } break;
      case DL_Range5: {
        lfStartDLYear = 1 - 2.0 / 12.0;
        lfEndDLYear = 1 + 2.0 / 12.0;
      } break;
      case DL_Range6: {
        lfStartDLYear = 3 - 2.0 / 12.0;
        lfEndDLYear = 3 + 2.0 / 12.0;
      } break;
      case DL_Range7: {
        lfStartDLYear = 5 - 3.0 / 12.0;
        lfEndDLYear = 5 + 3.0 / 12.0;
      } break;
      case DL_Range8: {
        lfStartDLYear = 7 - 4.0 / 12.0;
        lfEndDLYear = 7 + 4.0 / 12.0;
      } break;
      case DL_Range9: {
        lfStartDLYear = 10 - 4.0 / 12.0;
        lfEndDLYear = 10 + 4.0 / 12.0;
      } break;
      case DL_Range10: {
        lfStartDLYear = 9.5;
        lfEndDLYear = 10000.0;
      } break;
      case DL_RangeDate: {
        lfStartDLYear = atof(Cond.sMTDate1);
        lfEndDLYear = atof(Cond.sMTDate2);
        if (!IsEmpty(Info.GetMaturityTerm())) {
          std::string str = Info.GetMaturityTerm();
          fYear = CBondContainer::CalcRemainingDay(str) / 365.0;
        } else
          fYear = 0.0f;
      } break;
      case DL_Range21: {
        lfStartDLYear = 1.00001;
        lfEndDLYear = 10000.0;
      } break;
      default:
        break;
    }

    if (fYear <= lfEndDLYear && fYear > lfStartDLYear)
      return true;
    else
      continue;
  }

  return bRes;
}

const CSPString& CBondContainer::GetProdType(uint32_t nType) {
  return TypeNameManager::Get().GetTypeName(kTypeCategoryProd, nType);
}

const CSPString& CBondContainer::GetRatingLevel(uint32_t nIssuerRating) {
  return TypeNameManager::Get().GetTypeName(kTypeCategoryRating, nIssuerRating);
}

const CSPString& CBondContainer::GetCouponType(uint32_t nType) {
  return TypeNameManager::Get().GetTypeName(kTypeCategoryCoupon, nType);
}

const CSPString& CBondContainer::GetInstType(uint32_t nInst) {
  return TypeNameManager::Get().GetTypeName(kTypeCategoryInst, nInst);
}

bool CBondContainer::GetRightType(uint32_t nType) {
  if (nType == RightNo) return false;
  return true;
}

bool CBondContainer::IsETSBondType(const BLHCONDITION& Cond,
                                   const CBondInfo& Info) {
  int nSize = sizeof(Cond.nETSBond) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nETSBond[i] == 0x00) return false;

    switch (Cond.nETSBond[i]) {
      case CBondContainer::ETSBondAll:
        return true;
        break;
      case CBondContainer::ETSBondYes:
        if (Info.IsETSBond()) {
          return true;
        }
        break;
      case CBondContainer::ETSBondNo:
        if (!Info.IsETSBond()) {
          return true;
        }
        break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::IsSubordinatedType(const BLHCONDITION& Cond,
                                        const CBondInfo& Info) {
  int nSize = sizeof(Cond.nSubOrdinate) / sizeof(UINT);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nSubOrdinate[i] == 0x00) return false;

    switch (Cond.nSubOrdinate[i]) {
      case CBondContainer::SubOrdAll:
        return true;
        break;
      case CBondContainer::SubOrdinate:
        if (Info.IsBondSceniority()) {
          return true;
        }
        break;
      case CBondContainer::NonSubOrdinate:
        if (!Info.IsBondSceniority()) {
          return true;
        }
        break;
      default:
        break;
    }
  }
  return false;
}

bool CBondContainer::IsCorpBondType(const BLHCONDITION& Cond,
                                    const CBondInfo& Info) {
  int nSize = sizeof(Cond.nCorpBond) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nCorpBond[i] == 0x00) return false;

    switch (Cond.nCorpBond[i]) {
      case CBondContainer::CorpBondAll:
        return true;
        break;
      case CBondContainer::CorpBond_Public:
        if (Info.IsPubliceCorpBond()) {
          return true;
        }
        break;
      case CBondContainer::CorpBond_Private:
        if (Info.IsPrivateCorpBond()) {
          return true;
        }
        break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::IsPlatformType(const BLHCONDITION& Cond,
                                    const CBondInfo& Info) {
  if (!Info.IsMunicipal()) return false;
  int nSize = sizeof(Cond.nPlatform) / sizeof(uint32_t);

  CQBIssuerInfo& IMap = CQBIssuerInfo::instance();
  const IssuerInfo* pI = IMap.GetIssuerInfo(Info.GetIssuerCode());
  static char stPlatLevel[16 + 1] = {0};
  stPlatLevel[0] = '\0';
  if (pI != nullptr && !IsEmpty(pI->field((int)kIssuerInfo::Municipal_code))) {
    const QBPROVINCEINFO* pArea = CQBProvinceInfo::instance().GetProviceInfo(
        pI->field((int)kIssuerInfo::Municipal_code));
    if (pArea != nullptr) FIELDCOPY(stPlatLevel, pArea->Area_Level);
  }
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nPlatform[i]) {
      case CBondContainer::PlatforamAll:
        return true;
        break;
      case CBondContainer::Platforam_Province:
        if (strcmp(stPlatLevel, "PRN") == 0) {
          return true;
        }
        break;
      case CBondContainer::Platforam_City:
        if (strcmp(stPlatLevel, "CTY") == 0) {
          return true;
        }
        break;
      case CBondContainer::Platforam_Area:
        if (strcmp(stPlatLevel, "TWN") == 0) {
          return true;
        }
        break;
      case CBondContainer::Platforam_Other:
        if (strcmp(stPlatLevel, "VIL") == 0 ||
            strcmp(stPlatLevel, "ARE") == 0 ||
            strcmp(stPlatLevel, "IND") == 0 ||
            strcmp(stPlatLevel, "OTH") == 0) {
          return true;
        }
        break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::IsLocalBond(const BLHCONDITION& Cond,
                                 const CBondInfo& Info) {
  int nSize = sizeof(Cond.nLocalBond) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nLocalBond[i]) {
      case CBondContainer::LocalBondAll:
        return true;
        break;
      case CBondContainer::LocalBond_Normal:
        if (strcmp(Info.GetBondSubType(), "LLB") == 0 &&
            strcmp(Info.GetEntCor(), "SMB") == 0) {
          return true;
        }
        break;
      case CBondContainer::LocalBond_Special:
        if (strcmp(Info.GetBondSubType(), "LLB") == 0 &&
            strcmp(Info.GetEntCor(), "NMB") == 0) {
          return true;
        }
        break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::GetWarrType(const BLHCONDITION& Cond,
                                 const CBondInfo& Info) {
  int nSize = sizeof(Cond.nWarrant) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nWarrant[i] == 0x00) return false;

    switch (Cond.nWarrant[i]) {
      case CBondContainer::WarrPeople: {
        const char* pWarrant = Info.GetWarrant();
        if (pWarrant != nullptr && strstr(pWarrant, "GUA") != nullptr) {
          return true;
        }
      } break;
      case CBondContainer::WarrObject: {
        const char* pWarrant = Info.GetWarrant();
        if (pWarrant != nullptr && strstr(pWarrant, "SEC") != nullptr) {
          return true;
        }
      } break;
      case CBondContainer::WarrCRM: {
        const BOND_CRM_CLAUSE* pCrm =
            QBCRMBond::instance().GetBondByReferKey(Info.GetCombBondKey());
        if (pCrm) {
          std::string bklm;
          CBondInfo* pInfo;
          while (1) {
            std::string sBK(pCrm->BondKey);
            bklm = sBK + ".CIB";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CRM") == 0) return true;
              break;
            }
            bklm = sBK + ".SSE";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CRM") == 0) return true;
              break;
            }
            bklm = sBK + ".SZE";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CRM") == 0) return true;
              break;
            }
            break;
          }
        }
      }

      break;
      case CBondContainer::WarrCLN: {
        const BOND_CRM_CLAUSE* pCrm =
            QBCRMBond::instance().GetBondByReferKey(Info.GetCombBondKey());
        if (pCrm) {
          std::string bklm;
          CBondInfo* pInfo;
          while (1) {
            std::string sBK(pCrm->BondKey);
            bklm = sBK + ".CIB";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CLN") == 0) return true;
              break;
            }
            bklm = sBK + ".SSE";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CLN") == 0) return true;
              break;
            }
            bklm = sBK + ".SZE";
            pInfo = instance().GetBond(bklm);
            if (pInfo) {
              if (strcmp(pInfo->GetBondSubType(), "CLN") == 0) return true;
              break;
            }
            break;
          }
        }
      }

      break;
      case CBondContainer::WarrOther:
        return !Info.IsWarranted();
        break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::GetMunicpType(const BLHCONDITION& Cond,
                                   const CBondInfo& Info) {
  /*
  1、既是平台又是城投，选中平台；
  2、是城投，但非平台，选中城投；
  3、其余为非城投；
  */

  int nSize = sizeof(Cond.nMunicp) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    if (Cond.nMunicp[i] == CBondContainer::MunicNone) return false;

    switch (Cond.nMunicp[i]) {
      case CBondContainer::MunicYes: {
        if (Info.IsMunicipal()) {
          return true;
        }
      } break;
      case CBondContainer::MunicNo: {
        if (!Info.IsMunicipal()) {
          return true;
        }
      } break;
      case CBondContainer::MnuicPlatform: {
        if (Info.IsMunicipal() && Info.IsCBRC_Financing_Platform()) {
          return true;
        }
      } break;
      default:
        break;
    }
  }

  return false;
}

bool CBondContainer::RetrieveFromStatic(int bondType, const char* szType,
                                        std::vector<int>& array_result) {
  FilterTypes nType = (FilterTypes)bondType;
  if (nType == typeNone) {
    return true;
  }

  if (nType < typeMin || nType > typeMax) return false;

  bool bCheck2 = true;
  if (nType == typeBondType || nType == typeOption) {
    if (nullptr == szType || IsEmpty(szType)) nType = typeAll;
  }
  if (szType == nullptr) return false;

  HUGELOCK(m_mutex);
  int nSize = GetSize();
  switch (nType) {
    case typeBondType: {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (szType && strcmp(szType, info.GetBondSubType()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeExternal:
    case typeAttribute:
    case typeCoupon:
    case typeOption:
    case typeArgument:
    case typeDate:
    case typeRating:
      break;
    case typeBondID: {
      int nCount = 0;
      int nTypeLen = szType ? strlen(szType) : 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (GetMaturityBond(info)) continue;

        if (strncmp(info.GetCombBondCode(), szType, nTypeLen) == 0 ||
            strstr(info.GetBondShortName(), szType) ||
            strstr(const_cast<char*>(info.GetBondJianpin().c_str()), szType)) {
          // GetBondPinyin
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondKey: {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (GetMaturityBond(info)) continue;
        if (strcmp(szType, info.GetCombBondKey()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondExpiry: {
      int nCount = 0;
      time_t tnow = (time_t)szType;
      const char* expired = strBondLib_Expired() /*"已到期"*/;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (strcmp(info.GetRemainDate(), expired) != 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeMarketType: {
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (qstricmp(info.GetMarketType(), szType) == 0) {
          array_result.push_back(i);
        }
      }
    } break;
    case typeBondSubType: {
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (info.CheckBontSubType(szType)) array_result.push_back(i);
      }
    } break;
    case typeBondIDInSSE:  // 上证固收
    {
      int nCount = 0;
      int nTypeLen = szType ? strlen(szType) : 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (strcmp(info.GetListedMarket(), "SSE") != 0)
          continue;  // 剔除非上交所
        if (info.CheckAssetStatus(CBondContainer::AssetPri))
          continue;  // 剔除私募
        if (GetMaturityBond(info)) continue;

        if (strncmp(info.GetCombBondCode(), szType, nTypeLen) == 0 ||
            strstr(info.GetBondShortName(), szType) ||
            strstr(const_cast<char*>(info.GetBondJianpin().c_str()), szType)) {
          // GetBondPinyin
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondKeyInSSE:  // 上证固收
    {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond()) continue;
        if (strcmp(info.GetListedMarket(), "SSE") != 0)
          continue;  // 剔除非上交所
        if (info.CheckAssetStatus(CBondContainer::AssetPri))
          continue;  // 剔除私募
        if (GetMaturityBond(info)) continue;
        if (strcmp(szType, info.GetCombBondKey()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    default:
      ////SP_ASSERT( false );
      return false;
  }

  return true;
}

bool CBondContainer::RetrieveFromStaticCFETS(int bondType, const char* szType,
                                             std::vector<int>& array_result) {
  FilterTypes nType = (FilterTypes)bondType;
  if (nType == typeNone) {
    return true;
  }

  if (nType < typeMin || nType > typeMax) return false;

  bool bCheck2 = true;
  if (nType == typeBondType || nType == typeOption) {
    if (nullptr == szType ||
        IsEmpty(szType))  // && (nullptr == szSubType || IsEmpty(szSubType)) )
      nType = typeAll;
  }
  if (szType == nullptr) return false;

  HUGELOCK(m_mutex);
  int nSize = GetSize();
  switch (nType) {
    case typeBondType: {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange()) continue;
        if (szType && strcmp(szType, info.GetBondSubType()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeExternal:
    case typeAttribute:
    case typeCoupon:
    case typeOption:
    case typeArgument:
    case typeDate:
    case typeRating:
      break;
    case typeBondID: {
      int nCount = 0;
      int nTypeLen = szType ? strlen(szType) : 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange()) continue;
        if (GetMaturityBond(info)) continue;

        if (strncmp(info.GetCombBondCode(), szType, nTypeLen) == 0 ||
            strstr(info.GetBondShortName(), szType) ||
            strstr(const_cast<char*>(info.GetBondJianpin().c_str()), szType)) {
          // GetBondPinyin
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondKey: {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange()) continue;
        if (GetMaturityBond(info)) continue;
        if (strcmp(szType, info.GetCombBondKey()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondExpiry: {
      int nCount = 0;
      time_t tnow = (time_t)szType;
      const char* expired = strBondLib_Expired() /*"已到期"*/;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange()) continue;
        if (strcmp(info.GetRemainDate(), expired) != 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeMarketType: {
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange()) continue;
        if (qstricmp(info.GetMarketType(), szType) == 0) {
          array_result.push_back(i);
        }
      }
    } break;
    case typeBondSubType: {
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (info.IsAddIssueBond() || info.IsExchange())
          if (info.CheckBontSubType(szType)) array_result.push_back(i);
      }
    } break;
    default:
      ////SP_ASSERT(false);
      return false;
  }

  return true;
}

bool CBondContainer::RetrieveFromStaticSSEFI(int bondType, const char* szType,
                                             std::vector<int>& array_result) {
  FilterTypes nType = (FilterTypes)bondType;
  if (nType == typeNone) {
    return true;
  }

  if (nType < typeMin || nType > typeMax) return false;

  if (szType == nullptr) return false;

  HUGELOCK(m_mutex);
  int nSize = GetSize();
  switch (nType) {
    case typeBondID: {
      int nCount = 0;
      int nTypeLen = szType ? strlen(szType) : 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (strcmp(info.GetListedMarket(), "SSE") != 0) continue;
        if (info.IsAddIssueBond()) continue;
        if (GetMaturityBond(info)) continue;

        if (strncmp(info.GetCombBondCode(), szType, nTypeLen) == 0 ||
            strstr(info.GetBondShortName(), szType) ||
            strstr(const_cast<char*>(info.GetBondJianpin().c_str()), szType)) {
          // GetBondPinyin
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    case typeBondKey: {
      int nCount = 0;
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        const CBondInfo& info = ElementAtR(i);
        if (strcmp(info.GetListedMarket(), "SSE") != 0) continue;
        if (info.IsAddIssueBond()) continue;
        if (GetMaturityBond(info)) continue;
        if (strcmp(szType, info.GetCombBondKey()) == 0) {
          array_result.push_back(i);
          nCount++;
        }
      }
    } break;
    default:
      // SP_ASSERT(false);
      return false;
  }

  return true;
}

bool CBondContainer::RetrieveFromStatic(const BLHCONDITION& condStr,
                                        std::vector<int>& array_result,
                                        bool bSecondaryMarket) {
  if (condStr.nBrokId[0] == 0 && IsEmpty(condStr.sCompanyid)) {
    return false;
  }

  HUGELOCK(m_mutex);
  if (condStr.isAllin()) {
    int nSize = GetSize();
    array_result.reserve(nSize);
    for (int i = 0; i < nSize; i++)  // BIGLOOP
      array_result.push_back(i);
  } else {
    int nCount = 0;
    int nSize = GetSize();
    for (int i = 0; i < nSize; i++)  // BIGLOOP
    {
      bool bContinue = true;
      const CBondInfo& info = ElementAtR(i);
      if (bContinue && condStr.nValid != 0 && !IsBCQuoteValid(condStr, i))
        bContinue = false;
      if (bContinue && condStr.nBothFlg != 0 &&
          !IsHasPrice(condStr, i, BothValid))
        bContinue = false;
      if (bContinue && condStr.nNewFlg != 0 && !info.IsNewBond())
        bContinue = false;
      if (bContinue && condStr.nHasFlg != 0 && !IsHasPrice(condStr, i))
        bContinue = false;
      if (bContinue && condStr.nMatFlg != 0 && GetMaturityBond(info))
        bContinue = false;
      if (bContinue && condStr.nASemi != 0 && GetRebateBond(info))
        bContinue = false;
      if (bContinue && condStr.nMortgt != 0 && !info.IsMortgage())
        bContinue = false;
      if (bContinue && condStr.nCrosmk != 0 && !info.IsCrossMarket())
        bContinue = false;
      if (bContinue && condStr.nEntrTyp != 0 && !GetSOEenterType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nOffset != 0 && !GetBondOffsetEstPrc(condStr, i))
        bContinue = false;
      if (bContinue && !IsEmpty(condStr.sDiffPrice) &&
          !GetDiffPrice(condStr, i))
        bContinue = false;
      if (bContinue &&
          (!IsEmpty(condStr.sBPrice) || !IsEmpty(condStr.sBPriceEnd)) &&
          !CheckBidPrice(condStr, i))
        bContinue = false;
      if (bContinue &&
          (!IsEmpty(condStr.sOPrice) || !IsEmpty(condStr.sOPriceEnd)) &&
          !CheckOfrPrice(condStr, i))
        bContinue = false;
      if (bContinue && condStr.nCommonUse[0] != CBondContainer::CommAll &&
          !info.CheckCommonUseType(condStr))  // 常用
        bContinue = false;
      if (bContinue && condStr.nTypeNew[0] != newBondAll &&
          !info.CheckBondTypeNew(condStr))
        bContinue = false;
      if (bContinue && condStr.nIssuerRating[0] != RatingAll &&
          !GetMultiLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nOutlookRating[0] != OutlookRatingAll &&
          !GetOutlookRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nCDCRating[0] != CDCRatingAll &&
          !GetCDCRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCSIRating[0] != CSIRatingAll &&
          !GetCSIRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCBRRating[0] != CBRRatingAll &&
          !GetCBRRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nWarrant[0] != WarrAll &&
          !GetWarrType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCouponType[0] != CouponAll &&
          !GetMultiCouponType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nRight != RightAll &&
          GetRightType(condStr.nRight) != info.IsRight())
        bContinue = false;
      if (bContinue && condStr.nRange[0] != RangeAll &&
          !GetMaturityRange(condStr, info, bSecondaryMarket))
        bContinue = false;
      if (bContinue && condStr.nMunicp[0] != MunicAll &&
          !GetMunicpType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nInterbank != 0 && !info.IsInterbank())
        bContinue = false;
      if (bContinue && condStr.nExchange != 0 && !info.IsExchange())
        bContinue = false;
      if (bContinue && condStr.nInstion[0] != InstAll &&
          !GetMultiInstion(condStr, info))
        bContinue = false;
      if (bContinue && condStr.szIssuer[0][0] != '\0' &&
          !info.CheckIssuer(condStr))
        bContinue = false;
      if (bContinue && condStr.szSector[0][0] != '\0' &&
          !info.CheckSector(condStr))
        bContinue = false;
      if (bContinue && condStr.szSector2021[0][0] != '\0' &&
          !info.CheckSector2021(condStr))
        bContinue = false;
      if (bContinue && condStr.szArea[0][0] != '\0' && !info.CheckArea(condStr))
        bContinue = false;
      if (bContinue && condStr.szSubType[0][0] != '\0' &&
          !info.CheckBontSubType(condStr))
        bContinue = false;
      if (bContinue && condStr.nDebtRating[0] != DRatingNone &&
          !info.CheckDebtRating(condStr))
        bContinue = false;
      if (bContinue && condStr.nFinDebt[0] != FinDebtNone &&
          !info.CheckFinDebt(condStr))
        bContinue = false;
      if (bContinue && condStr.nPlatform[0] != PlatforamAll &&
          !IsPlatformType(condStr, info))  // 平台债
        bContinue = false;
      if (bContinue && condStr.nLocalBond[0] != LocalBondAll &&
          !IsLocalBond(condStr, info))  // 地方债
        bContinue = false;
      // add  by lbl  NCD
      if (bContinue && condStr.nNCDRating[0] != NCDRatingAll &&
          !info.CheckNCDRating(condStr))  // NCD
        bContinue = false;

      // end

      if (bContinue && condStr.nIssueYear[0] != 0 &&
          !info.CheckIssueYear(condStr))
        bContinue = false;
      if (bContinue && condStr.nStateType != 0 && !GetStateType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.szIssueDateB[0] != 0 &&
          condStr.szIssueDateE[0] != 0 && !GetIssueStartDate(condStr, info))
        bContinue = false;
      if (bContinue && condStr.szUnderwriter[0] != 0 &&
          !info.CheckUnderwriter(condStr))
        bContinue = false;
      if (bContinue && condStr.nCreditBond != 0 && !info.IsCreditBond(condStr))
        bContinue = false;
      if (bContinue && !info.IsInDays(condStr)) bContinue = false;
      if (bContinue && condStr.nETSBond[0] != CBondContainer::ETSBondAll &&
          !IsETSBondType(condStr, info))  // 永续债
        bContinue = false;
      if (bContinue && condStr.nCorpBond[0] != CBondContainer::CorpBondAll &&
          !IsCorpBondType(condStr, info))  // 公司债
        bContinue = false;
      if (bContinue && condStr.nAssetStatus[0] != CBondContainer::AssetAll &&
          !info.CheckAssetStatus(condStr))  // 发行
        bContinue = false;
      if (bContinue && !IsEmpty(condStr.sBidCdc) &&
          !GetBidCdcCompare(condStr, i))  // bid-中债
        bContinue = false;
      if (bContinue && !IsEmpty(condStr.sCdcOfr) &&
          !GetCdcOfrCompare(condStr, i))  // 中债-ofr
        bContinue = false;
      if (bContinue && condStr.nExpireInHoliday == 1 &&
          info.IsExpireInHoliday())  // 不含假期
        bContinue = false;
      if (bContinue) {
        array_result.push_back(i);
        nCount++;
      }
    }
  }

  return true;
}

bool CBondContainer::GetBondInfo(const char* szCode, const char* szMarket,
                                 CBondInfo* pInfo, int* pid) {
  if (nullptr == szCode || IsEmpty(szCode)) return false;
  void* pArrayID = nullptr;
  std::string sKey(szCode);
  if (szMarket && !IsEmpty(szMarket)) {
    if (strcmp(szMarket, CBondContainer::lmCIB) == 0)
      sKey += ".IB";
    else if (strcmp(szMarket, CBondContainer::lmSSE) == 0)
      sKey += ".SH";
    else if (strcmp(szMarket, CBondContainer::lmSZE) == 0)
      sKey += ".SZ";
  }

  int bid = GetBondIndexByCodeImpl(sKey.c_str(), sKey.size());
  if (bid >= 0 && bid < GetSize()) {
    const CBondInfo& info = ElementAtR(bid);
    if (pInfo) *pInfo = info;
    if (pid) *pid = bid;
    return true;
  }

  return false;
}

bool CBondContainer::GetBondInfoByKey(const char* szKey, const char* szMarket,
                                      CBondInfo* pInfo, int* pid) {
  if (nullptr == szKey || IsEmpty(szKey)) {
    // LOGDEBUG("invalid szKey:nullptr or blank");
    ////BASSERTS(0, "invalid szKey:nullptr or blank");
    return false;
  }
  void* pArrayID = nullptr;
  std::string sKey;
  if (szMarket && !IsEmpty(szMarket))
    sKey = std::string(szKey) + "." + std::string(szMarket);
  else
    sKey = std::string(szKey);

  int bid = -1;
  {
    // READLOCK(m_mutex);
    int bid = GetBondIndexImpl(sKey.c_str(), sKey.size());
    if (bid >= 0 && bid < GetSize()) {
      const CBondInfo& info = ElementAtR(bid);
      if (pInfo) *pInfo = info;
      if (pid) *pid = bid;
      return true;
    }
  }
  if (sKey.size() < 10) {
    // BASSERTS(sKey.size() > 10, "invalid item in m_keymap:%s-->%d",
    // sKey.c_str(), bid);
  }
  ////LOGEMERG("invalid item in m_keymap:%s-->%d", sKey,bid);
  return false;
}

const CAdditionBondInfo* CBondContainer::GetAdditionBondInfo(int nIndex) {
  // NEEDLOCK,NEEDCHECK
  // 直接返回CAdditionBondInfo指针
  if (nIndex < 0 || nIndex >= (int)m_vctaddi.size()) return nullptr;
  return m_vctaddi[nIndex];
}

bool CBondContainer::GetBondInfoByCombCode(const char* szCode, CBondInfo* pInfo,
                                           int* pid) {
  if (nullptr == szCode || IsEmpty(szCode)) return false;

  int bid = GetBondIndexByCodeImpl(szCode, -1);
  if (bid >= 0 && bid < GetSize()) {
    READLOCK(m_mutex);
    const CBondInfo& info = ElementAtR(bid);
    if (pInfo) *pInfo = info;
    if (pid) *pid = bid;
    return true;
  }

  return false;
}

bool CBondContainer::GetBondInfoByCombKey(const char* szKey, CBondInfo* pInfo,
                                          int* pid) {
  if (nullptr == szKey || IsEmpty(szKey)) {
    // LOGDEBUG("invalid szKey:nullptr or blank");
    ////BASSERTS(0, "invalid szKey:nullptr or blank");
    return false;
  }
  int bid = -1;
  {
    bid =
        GetBondIndexImpl(szKey, -1);  // 拿到bid,确保对应的CBondInfo不会移动位置
    if (bid >= 0 && bid < GetSize()) {
      READLOCK(m_mutex);
      const CBondInfo& info = ElementAtR(bid);
      if (pInfo) *pInfo = info;
      if (pid) *pid = bid;
      return true;
    }
  }

  // LOGEMERG("invalid item in m_keymap:%s-->%d", szKey,bid);
  return false;
}

bool CBondContainer::GetBondOffsetEstPrc(const BLHCONDITION& Cond, int nID) {
  if (nID < 0 || nID >= GetSize()) return false;

  if (Cond.nBkClnt != 0) return GetCltOffsetEstPrc(Cond, nID);

  SetBKQuoteDiff2CDCFlag(Cond.sCompanyid, nID, 0, 0);

  BKQUOTE quote = {0};
  if (instance().GetBankInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    pRep->m_BidDiff2CDCFlag = 0;
    pRep->m_OfrDiff2CDCFlag = 0;
    bool needCheck = false;
    double fDelta = 0;
    if (Cond.bDiff2CDC[0] == 1) {
      if (!IsEmpty(Cond.sDiff2CDC[0])) {
        fDelta = atof(Cond.sDiff2CDC[0]) / 100;
        needCheck = true;
      }
    } else {
      READLOCK(m_mutex);
      const CBondInfo& info = ElementAtR(nID);
      for (int i = 1; i < 9; i++) {
        if (Cond.bDiff2CDC[i] == 1 && info.CheckBondTypeNew(newBondAll + i)) {
          if (!IsEmpty(Cond.sDiff2CDC[i])) {
            fDelta = atof(Cond.sDiff2CDC[i]) / 100;
            needCheck = true;
            break;
          }
        }
      }
    }
    if (!needCheck) return false;
    bool bIsCDCAuthValid = true;
    {
      CBondInfo* pBond = nullptr;
      pBond = GetBond(nID);
      if (pBond != nullptr) {
        bIsCDCAuthValid = pBond->IsCDCAuthValid();
      }
    }

    if (strcmp(pRep->m_BidStatus, "0") != 0) {
      if (CBondCDCPriceInfo::instance().GetEstimatePriceGap(
              bIsCDCAuthValid, nID, CBondCDCPriceInfo::price_type_yield, true,
              pRep->m_Bid) > fDelta)
        pRep->m_BidDiff2CDCFlag = 1;
    }
    if (strcmp(pRep->m_OfrStatus, "0") != 0) {
      if (CBondCDCPriceInfo::instance().GetEstimatePriceGap(
              bIsCDCAuthValid, nID, CBondCDCPriceInfo::price_type_yield, false,
              pRep->m_Ofr) > fDelta)
        pRep->m_OfrDiff2CDCFlag = 1;
    }
    SetBKQuoteDiff2CDCFlag(Cond.sCompanyid, nID, pRep->m_BidDiff2CDCFlag,
                           pRep->m_OfrDiff2CDCFlag);
    if (pRep->m_BidDiff2CDCFlag || pRep->m_OfrDiff2CDCFlag) return true;
  }
  return false;
}

bool CBondContainer::IsBCQuoteValid(const BLHCONDITION& Cond, int nID) {
  CBondContainer& cont = instance();
  if (nID < 0 || nID >= cont.GetSize()) return false;

  if (Cond.nBkClnt != 0) return IsQBQuoteValid(Cond, nID);

  BKQUOTE quote = {0};
  if (instance().GetBankInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    if ((strcmp(pRep->m_BidStatus, "0") != 0 && !IsEmpty(pRep->m_Bid)) ||
        (strcmp(pRep->m_OfrStatus, "0") != 0 &&
         !IsEmpty(pRep->m_Ofr)))  // 有效报价，referred报价
      return true;
  }
  return false;
}

bool CBondContainer::IsQBQuoteValid(const BLHCONDITION& Cond, int nID) {
  BKQUOTE quote = {0};
  if (instance().GetClentInfoById(Cond.sCompanyid, nID, quote)) {
    BKQUOTE* pRep = &quote;
    if ((strcmp(pRep->m_BidStatus, "0") != 0 && !IsEmpty(pRep->m_Bid)) ||
        (strcmp(pRep->m_OfrStatus, "0") != 0 && !IsEmpty(pRep->m_Ofr)))
      return true;
  }
  return false;
}

void CBondContainer::SetBKQuoteDiff2CDCFlag(const char* sCompanyID, int nIndex,
                                            char cBidFlag, char cOfrFlag) {
  class BkQuoteDiffWriter : public CBondBankRep::ApplyCallback {
    char m_bidflag;
    char m_ofrflag;

   public:
    BkQuoteDiffWriter(char cBidFlag, char cOfrFlag)
        : m_bidflag(cBidFlag), m_ofrflag(cOfrFlag) {}
    virtual bool DoModify(BKQUOTE& bkquote) {
      bkquote.m_BidDiff2CDCFlag = m_bidflag;
      bkquote.m_OfrDiff2CDCFlag = m_ofrflag;
      return false;
    }
  };

  CBondBankRep* ptmp = GetBankRep(nIndex);
  if (ptmp) {
    BkQuoteDiffWriter writer(cBidFlag, cOfrFlag);
    ptmp->ApplyModify(false, sCompanyID, &writer);
  }
  return;
}

bool CBondContainer::GetCompanyRepById(int nId, REPORT& stRep) {
  if (nId < 0 || nId >= GetSize()) return false;
  bool bRes = false;
  memset(&stRep, 0, sizeof(REPORT));
  CBondCompanyRep* ptmp = GetCompanyRep(nId);
  if (ptmp && ptmp->GetSize() > 0) {
    class CompanyRepCallback : public CBondCompanyRep::ApplyCallback {
      REPORT& m_report;
      bool& m_ret;

     public:
      CompanyRepCallback(REPORT& rpt, bool& ret) : m_report(rpt), m_ret(ret) {}
      bool operator()(CBondCompanyRep* ptemp) {
        if (ptemp) ptemp->ApplyAccess(true, "", this);
        return m_ret;
      }
      virtual bool DoAccess(const REPORT& rep) {
        if (atoi(rep.m_bidinfo.m_rebate) == 1 ||
            !IsEmpty(rep.m_bidinfo.m_sPrice)) {
          if (atof(rep.m_bidinfo.m_sPrice) >=
              atof(m_report.m_bidinfo.m_sPrice)) {
            m_report.m_bidinfo = rep.m_bidinfo;
            m_report.m_time = max(rep.m_time, m_report.m_time);
          }
          m_ret = true;
        }
        if (atoi(rep.m_askinfo.m_rebate) == 1 ||
            !IsEmpty(rep.m_askinfo.m_sPrice)) {
          if (IsEmpty(m_report.m_askinfo.m_sPrice) ||
              atof(rep.m_askinfo.m_sPrice) <=
                  atof(m_report.m_askinfo.m_sPrice)) {
            m_report.m_askinfo = rep.m_askinfo;
            m_report.m_time = max(rep.m_time, m_report.m_time);
          }
          m_ret = true;
        }
        if (!IsEmpty(rep.m_indx_info.m_price)) {
          m_report = rep;
          // stRep.m_indx_info = rep.m_indx_info;
          m_ret = true;
        }
        return true;
      }
    };
    return CompanyRepCallback(stRep, bRes)(ptmp);
  }

  return bRes;
}

static bool UpdatePriceBySettlement(PRICE& price, BYTE btPriceFilter) {
  PRICE_SETTLEMENT_LIST pes;
  CBondContainer::DecodeSettlement(price, pes);

  BYTE settlement = btPriceFilter & 0x0F;
  BYTE quoteType = btPriceFilter & 0xF0;

  bool found = false;
  std::string strVol, strDesc, strIntp;
  strVol.reserve(sizeof(price.m_sVolume));
  strDesc.reserve(sizeof(price.m_description));
  strIntp.reserve(sizeof(price.m_interpret));

  bool bargin0 = false;
  if (qstricmp(price.m_sPrice, "Bid") == 0 ||
      qstricmp(price.m_sPrice, "Ofr") == 0)
    bargin0 = true;

  for (auto& ps : pes) {
    if (settlement > 0x0 && 0 == (ps.m_type & settlement))
      continue;  // 清算速度不匹配
    // vol
    bool bargin = bargin0;
    bargin |= (ps.m_bargin > '0');
    bool pstar = (ps.m_pstar == '1' && !bargin);
    bool checked = false;
    if (quoteType == 0x00)
      checked = true;
    else {
      if ((quoteType & 0x10) && !bargin && !pstar) checked = true;  // 实盘
      if ((quoteType & 0x20) && pstar) checked = true;   // 可部分执行
      if ((quoteType & 0x40) && bargin) checked = true;  // 意向价
    }
    if (!checked) continue;  // 报价类型不匹配

    if (!strVol.empty()) strVol.append("+");
    strVol.append(ps.m_vol);

    if (!strDesc.empty()) strDesc.append("+");
    if (strlen(ps.m_desc) > 0)
      strDesc.append(ps.m_vol).append("(").append(ps.m_desc).append(")");
    else
      strDesc.append(ps.m_vol);

    if (!strIntp.empty()) strIntp.append(";");
    strIntp.append(ps.m_original);

    found = true;
  }

  if (!found) {
    memset(&price, 0, sizeof(PRICE));
    return false;
  } else {
    FIELDCOPY(price.m_sVolume, strVol.c_str());
    if (strDesc.find('(') != -1)
      FIELDCOPY(price.m_description, strDesc.c_str());
    else
      memset(price.m_description, 0, sizeof(price.m_description));
    FIELDCOPY(price.m_interpret, strIntp.c_str());
  }

  return true;
}

bool CBondContainer::GetCompanyRepByIdAndSettlement(
    int nId, const char* szBrokerId, BYTE btSettlement,
    REPORT& stRep)  // 根据债券szBondKey和公司名称得到报价
{
  if (btSettlement == 0) return GetCompanyRepById(nId, szBrokerId, stRep);
  CBondCompanyRep* ptmp = GetCompanyRep(nId);
  if (ptmp && ptmp->GetCompanyRepByKey(szBrokerId, stRep)) {
    bool ret1 = UpdatePriceBySettlement(stRep.m_bidinfo, btSettlement);
    bool ret2 = UpdatePriceBySettlement(stRep.m_askinfo, btSettlement);
    return ret1 || ret2;
  }

  return false;
}

bool CBondContainer::GetBrokerMixedBPRepById(
    int nId, const char* szContributorId,
    REPORT& stRep)  // 根据清算速度得到综合最优报价
{
  if (nId < 0 || nId >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetBrokerMixedBPRep(nId);
  if (ptmp && ptmp->GetCompanyRepByKey(szContributorId, stRep)) {
    return true;
  }
  return false;
}

bool CBondContainer::GetBrokerMixedBPRepByIdAndPriceFilter(
    int nId, const char* szContributorId, BYTE btPriceFilter,
    REPORT& stRep)  // 根据债券szBondKey和公司名称得到报价
{
  if (nId < 0 || nId >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetBrokerMixedBPRep(nId);
  if (ptmp && ptmp->GetCompanyRepByKey(szContributorId, stRep)) {
    if ((btPriceFilter & 0xFF) == 0) return true;  // 无报价类型筛选

    bool ret1 = UpdatePriceBySettlement(stRep.m_bidinfo, btPriceFilter);
    bool ret2 = UpdatePriceBySettlement(stRep.m_askinfo, btPriceFilter);
    return ret1 || ret2;
  }
  return false;
}

bool CBondContainer::GetCompanyBidInfoById(
    const BLHCONDITION& Cond, int nID) {  // 不满足过滤条件返回 false
  if (nID < 0 || nID >= GetSize()) return false;

  if (IsEmpty(Cond.sBPrice) && IsEmpty(Cond.sBPriceEnd)) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->TestBidPrice(Cond)) return true;

  return false;
}

bool CBondContainer::GetCompanyOfrInfoById(
    const BLHCONDITION& Cond, int nID) {  // 不满足过滤条件返回 false
  if (nID < 0 || nID >= GetSize()) return false;

  if (IsEmpty(Cond.sOPrice) && IsEmpty(Cond.sOPriceEnd)) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->TestOfrPrice(Cond)) return true;

  return false;
}

bool CBondContainer::GetBankCltBidInfoById(const BLHCONDITION& Cond, int nID) {
  class BkQuoteBidAccessor : public CBondBankRep::ApplyCallback {
    char m_szBprice[10];
    char m_szBpriceEnd[10];
    // float			m_bprice;
    int m_nBondIndex;
    bool m_bIsCDCAuthValid;
    bool m_result;
    // uint32_t			m_bidflag;	//BLHCONDITION.nBpcCnd
   public:
    BkQuoteBidAccessor(const char* pBprice, const char* pBpriceEnd, int nID,
                       bool bIsCDCAuthValid)
        : m_nBondIndex(nID),
          m_result(true),
          m_bIsCDCAuthValid(bIsCDCAuthValid) {
      strcpy(m_szBprice, pBprice);
      strcpy(m_szBpriceEnd, pBpriceEnd);
    }

    bool GetResult() const { return m_result; }
    virtual bool DoAccess(const BKQUOTE& quote) {
      double dGap = 0.00001;
      if (!(IsEmpty(quote.m_Bid) || strcmp(quote.m_BidStatus, "0") == 0)) {
        double dGap = CBondCDCPriceInfo::instance().GetEstimatePriceGap(
            m_bIsCDCAuthValid, m_nBondIndex,
            CBondCDCPriceInfo::price_type_yield, true, quote.m_Bid);
        if (dGap > INVALID_CDC_VALUE) {
          dGap = fabs(dGap) * 100.00;
        }
      }

      if (dGap <= 0.00001) {
        m_result = false;
        return false;
      }

      float fBid = dGap;

      bool bRet = false;
      if (!IsEmpty(m_szBprice) && !IsEmpty(m_szBpriceEnd)) {
        bRet = (fBid > (atof(m_szBprice) - 0.00001));
        if (bRet) bRet = (fBid < (atof(m_szBpriceEnd) + 0.00001));
      } else {
        if (!IsEmpty(m_szBprice)) bRet = (fBid > (atof(m_szBprice) - 0.00001));

        if (!bRet && !IsEmpty(m_szBpriceEnd))
          bRet = (fBid < (atof(m_szBpriceEnd) + 0.00001));
      }

      m_result = bRet;

      return m_result;
    }
  };

  if (nID < 0 || nID >= GetSize()) return false;

  float fDiffprc = atof(Cond.sBPrice);
  CBondBankRep* ptmp = GetClntRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    int nOptType = CBondCDCPriceInfo::est_type_invalid;
    bool bIsCDCAuthValid = true;

    CBondInfo* pInfo = nullptr;
    pInfo = GetBond(nID);
    if (pInfo->IsCDCAuthValid()) {
      bIsCDCAuthValid = pInfo->IsCDCAuthValid();
    }
    BkQuoteBidAccessor accessor(Cond.sBPrice, Cond.sBPriceEnd, nID,
                                bIsCDCAuthValid);
    ptmp->ApplyAccess(true, "", &accessor);
    return accessor.GetResult();  // 默认true;
  }

  return true;
}

bool CBondContainer::GetBankCltOfrInfoById(const BLHCONDITION& Cond, int nID) {
  class BkQuoteOfrAccessor : public CBondBankRep::ApplyCallback {
    char m_szOprice[10];  // sOPrice
    char m_szOpriceEnd[10];
    int m_nBondIndex;
    bool m_bIsCDCAuthValid;
    bool m_result;
    // uint32_t			m_ofrflag;	//BLHCONDITION.nOpcCnd
   public:
    BkQuoteOfrAccessor(const char* pOprice, const char* pOpriceEnd, int nID,
                       bool bIsCDCAuthValid)
        : m_nBondIndex(nID),
          m_result(true),
          m_bIsCDCAuthValid(bIsCDCAuthValid) {
      strcpy(m_szOprice, pOprice);
      strcpy(m_szOpriceEnd, pOpriceEnd);
    }

    bool GetResult() const { return m_result; }

    virtual bool DoAccess(const BKQUOTE& quote) {
      double dGap = 0.00001;
      if (!(IsEmpty(quote.m_Ofr) || strcmp(quote.m_OfrStatus, "0") == 0)) {
        dGap = CBondCDCPriceInfo::instance().GetEstimatePriceGap(
            m_bIsCDCAuthValid, m_nBondIndex,
            CBondCDCPriceInfo::price_type_yield, false, quote.m_Ofr);
        if (dGap > INVALID_CDC_VALUE) dGap = fabs(dGap) * 100.00;
      }

      if (dGap <= 0.00001) {
        m_result = false;
        return false;
      }

      float fOfr = dGap;

      bool bRet = false;
      if (!IsEmpty(m_szOprice) && !IsEmpty(m_szOpriceEnd)) {
        bRet = (fOfr > (atof(m_szOprice) - 0.00001));
        if (bRet) bRet = (fOfr < (atof(m_szOpriceEnd) + 0.00001));
      } else {
        if (!IsEmpty(m_szOprice)) bRet = (fOfr > (atof(m_szOprice) - 0.00001));

        if (!bRet && !IsEmpty(m_szOpriceEnd))
          bRet = (fOfr < (atof(m_szOpriceEnd) + 0.00001));
      }

      m_result = bRet;

      return bRet;
    }
  };

  if (nID < 0 || nID >= GetSize()) return false;

  float fDiffprc = atof(Cond.sOPrice);
  CBondBankRep* ptmp = GetClntRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    bool bIsCDCAuthValid = true;
    CBondInfo* pInfo = nullptr;
    pInfo = GetBond(nID);
    if (pInfo->IsCDCAuthValid()) {
      bIsCDCAuthValid = pInfo->IsCDCAuthValid();
    }
    BkQuoteOfrAccessor accessor(Cond.sOPrice, Cond.sOPriceEnd, nID,
                                bIsCDCAuthValid);
    ptmp->ApplyAccess(true, "", &accessor);
    return accessor.GetResult();  // 默认true;
  }

  return true;
}

bool CBondContainer::GetClentInfoById(const std::string& szKey, int nID,
                                      BKQUOTE& quote) {
  if (nID < 0 || nID >= GetSize()) return false;
  memset(&quote, 0, sizeof(quote));
  CBondBankRep* ptmp = GetClntRep(nID);
  return ptmp ? ptmp->GetBankRepByKey(szKey, quote) : false;
}

bool CBondContainer::GetCompanyRepByKey(const char* szBondKey, REPORT& stRep) {
  /*
  接口改造正则表达式:
  (\w+)\s*\*\s*(\w+)\s*=\s*instance\(\).(\w+)\([\w\.]+,\w+\);(\s*\n\t*)if\(\s*\w+\s*\)\s*\n\s*{
  $1 quote={0};if(instance().$3($4,quote))$5{$1* $2=&quote;
  */
  int nId = 0;
  if (GetBondInfoByCombKey(szBondKey, nullptr, &nId)) {
    return GetCompanyRepById(nId, stRep);
  }
  return false;
}

bool CBondContainer::GetCompanyRepByKeyAndSettlement(const char* szComboBondKey,
                                                     const char* szBrokerId,
                                                     BYTE btSettlement,
                                                     REPORT& stRep) {
  int nId = 0;
  if (GetBondInfoByCombKey(szComboBondKey, nullptr, &nId)) {
    return GetCompanyRepByIdAndSettlement(nId, szBrokerId, btSettlement, stRep);
  }
  return false;
}

bool CBondContainer::GetCompanyInfoById(int nID) {
  if (nID < 0 || nID >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  class CompanyInfoFinder : public CBondCompanyRep::ApplyCallback {
    bool m_found;

   public:
    bool operator()(CBondCompanyRep* ptmp) {
      m_found = false;
      if (ptmp) ptmp->ApplyAccess(true, "", this);
      return m_found;
    }
    virtual bool DoAccess(const REPORT& rpt) {
      if (strcmp(rpt.m_bidinfo.m_price_status, "0") == 0 &&
          strcmp(rpt.m_askinfo.m_price_status, "0") == 0)
        return true;

      if ((atoi(rpt.m_bidinfo.m_rebate) == 1 &&
           strcmp(rpt.m_bidinfo.m_price_status, "0") != 0) ||
          (atoi(rpt.m_askinfo.m_rebate) == 1 &&
           strcmp(rpt.m_askinfo.m_price_status, "0") != 0)) {
        m_found = true;
        return false;
      }

      if ((!IsEmpty(rpt.m_bidinfo.m_sPrice) &&
           strcmp(rpt.m_bidinfo.m_price_status, "0") != 0) ||
          (!IsEmpty(rpt.m_askinfo.m_sPrice) &&
           strcmp(rpt.m_askinfo.m_price_status, "0") != 0)) {
        m_found = true;
        return false;
      }
      return true;  // 表示继续遍历
    }
  };
  return CompanyInfoFinder()(ptmp);
}

bool CBondContainer::GetCpicCompanyInfoById(int nID, bool bBuyPool /*= true*/) {
  if (nID < 0 || nID >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    class CpicCompanyInfoFinder : CBondCompanyRep::ApplyCallback {
      bool m_found;
      bool m_buy_pool;

     public:
      bool operator()(CBondCompanyRep* ptmp, bool bBuyPool) {
        m_found = false;
        m_buy_pool = bBuyPool;
        if (ptmp) ptmp->ApplyAccess(true, "", this);
        return m_found;
      }
      virtual bool DoAccess(const REPORT& rpt) {
        if (m_buy_pool)  // 买入池
        {
          if (strcmp(rpt.m_bidinfo.m_price_status, "0") == 0 &&
              strcmp(rpt.m_askinfo.m_price_status, "0") == 0)
            return true;

          if ((atoi(rpt.m_bidinfo.m_rebate) == 1 &&
               strcmp(rpt.m_bidinfo.m_price_status, "0") != 0) ||
              (atoi(rpt.m_askinfo.m_rebate) == 1 &&
               strcmp(rpt.m_askinfo.m_price_status, "0") != 0)) {
            m_found = true;
            return false;
          }

          if ((!IsEmpty(rpt.m_bidinfo.m_sPrice) &&
               strcmp(rpt.m_bidinfo.m_price_status, "0") != 0) ||
              (!IsEmpty(rpt.m_askinfo.m_sPrice) &&
               strcmp(rpt.m_askinfo.m_price_status, "0") != 0)) {
            m_found = true;
            return false;
          }
        } else  // 卖出池
        {
          if (strcmp(rpt.m_bidinfo.m_price_status, "0") == 0) return true;

          if ((atoi(rpt.m_bidinfo.m_rebate) == 1 &&
               strcmp(rpt.m_bidinfo.m_price_status, "0") != 0)) {
            m_found = true;
            return false;
          }

          if ((!IsEmpty(rpt.m_bidinfo.m_sPrice) &&
               strcmp(rpt.m_bidinfo.m_price_status, "0") != 0)) {
            m_found = true;
            return false;
          }
        }
        return true;
      }
    };
    return CpicCompanyInfoFinder()(ptmp, bBuyPool);
  }

  return false;
}

bool CBondContainer::GetCompanyRepById(int nId, const char* szBrokerId,
                                       REPORT& stRep) {
  if (nId < 0 || nId >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nId);
  if (ptmp && ptmp->GetCompanyRepByKey(szBrokerId, stRep)) {
    return true;
  }

  return false;
}

bool CBondContainer::GetCompanyRepByIdEx(
    int nId, const char* szKey, REPORT& stRep,
    int nFlag)  // flag = 0 取最新，1 取最新有效，2 取最新双边
{
  memset(&stRep, 0, sizeof(REPORT));
  if (nId < 0 || nId >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nId);
  return ptmp ? ptmp->GetReport(szKey, stRep, nFlag) : false;
}

bool CBondContainer::GetCompanyIdFromRep(int nId, const char* szKey, char* buf,
                                         int capcity) {
  // 避免拷贝REPORT结构体的开销
  CBondCompanyRep* ptmp = GetCompanyRep(nId);
  if (ptmp) {
    const char* field =
        (const char*)ptmp->GetReportField(szKey, (int)kReportField::CompanyId);
    if (field) {
      FIELDCOPYN(buf, capcity, field);
      return true;
    }
  }
  return false;
}

bool CBondContainer::GetCompanyRepByKey(const char* szComboBondKey,
                                        const char* szBrokerId, REPORT& stRep) {
  int nId = 0;
  if (GetBondInfoByCombKey(szComboBondKey, nullptr, &nId)) {
    CBondCompanyRep* ptmp = GetCompanyRep(nId);
    if (ptmp && ptmp->GetCompanyRepByKey(szBrokerId, stRep)) {
      return true;
    }
  }
  return false;
}

bool CBondContainer::GetXCQuoteByKey(const char* szBondKey,
                                     const char* szMarket, XCQUOTE& quote) {
  int nId = 0;
  if (GetBondInfoByKey(szBondKey, szMarket, nullptr, &nId)) {
    CXCQuoteRep* ptmp = GetXCQuote(nId);
    if (ptmp && ptmp->GetQuoteByKey(szMarket, quote)) {
      return true;
    }
  }
  return false;
}

bool CBondContainer::GetCFETSQuoteByKey(const char* szBondKey,
                                        const char* szMarket,
                                        CCFETSQuote::CFETSQUOTETYPE nType,
                                        CFETSQUOTE& quote, int clearspeed) {
  int nId = 0;
  if (GetBondInfoByKey(szBondKey, szMarket, NULL, &nId)) {
    CSSReportManager<CCFETSQuoteRep>* pManager = CfetsRepMng;
    if (pManager) {
      CReportManagerBase::Scoped l(pManager->GetMutex());
      CCFETSQuoteRep* ptmp = GetCFETSQuote(nId);
      if (ptmp && ptmp->GetQuoteByKey(nType, quote)) {
        if (clearspeed > 0) {
          // 筛选
          return FilterQuoteByClearSpeed(quote, clearspeed);
        }
        return true;
      }
    }
  }
  return false;
}

bool CBondContainer::FilterQuoteByClearSpeed(CFETSQUOTE& quote,
                                             BYTE btSettlement) {
  bool bBidValid{true}, bOfrValid{true};
  if ((GetCFETSSpeedType(quote.m_bidVolDescription) & btSettlement) == 0) {
    bBidValid = false;
    _InitializeString(quote.m_BidPriceYield);
    _InitializeString(quote.m_BidPriceClean);
    _InitializeString(quote.m_BidPriceFull);
    _InitializeString(quote.m_BidVol);
    _InitializeString(quote.m_bidVolDescription);
    quote.m_BidCompanyName = "";
    quote.m_bidversion = 0;
  }
  if ((GetCFETSSpeedType(quote.m_ofrVolDescription) & btSettlement) == 0) {
    bOfrValid = false;
    _InitializeString(quote.m_OfrPriceYield);
    _InitializeString(quote.m_OfrPriceClean);
    _InitializeString(quote.m_OfrPriceFull);
    _InitializeString(quote.m_OfrVol);
    _InitializeString(quote.m_ofrVolDescription);
    quote.m_OfrCompanyName = "";
    quote.m_ofrversion = 0;
  }
  if (!bBidValid && !bOfrValid) {
    quote.m_time = 0;
  }
  return bBidValid || bOfrValid;
}

void CBondContainer::CalcIssueDateRange() {  // 计算最大最小发行日
  int nMin = 99999999;
  int nMax = -1;

  m_nMinIssueDate = 0;
  m_nMaxIssueDate = 0;
  int nSize = GetSize();
  HUGELOCK(m_mutex);
  for (int i = 0; i < nSize; i++)  // BIGLOOP
  {
    const CBondInfo& info = ElementAtR(i);
    int nDate = atoi(info.GetIssueStartDate());
    if (nDate > 19000000) {
      nMin = std::min(nMin, nDate);
      nMax = std::max(nMax, nDate);
    }
  }
  if (nMin < 99999999) m_nMinIssueDate = nMin;
  if (nMax > 0) m_nMaxIssueDate = nMax;
  return;
}

int CBondContainer::GetMinIssueDate() { return m_nMinIssueDate; }

int CBondContainer::GetMaxIssueDate() { return m_nMaxIssueDate; }

double CBondContainer::GetBondActualIssueAmount(int bondIndex) {
  if (!IsValidIndex(bondIndex)) return -1e-6;
  const CBondInfo& bi = ElementAtR(bondIndex);

  std::set<int>* pSet = NULL;
  GetAdditionList(bondIndex, pSet);
  double amount = bi.GetActualIssueAmount();
  if (pSet) {
    for (std::set<int>::iterator itset = pSet->begin(); itset != pSet->end();
         ++itset) {
      amount += GetBond(*itset)->GetActualIssueAmount();
    }
  }
  return amount;
}

time_t CBondContainer::GetModifyTimeFast(const std::string& szKey, int nID) {
  if (nID < 0 || nID >= GetSize()) return 0;
  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  return ptmp ? ptmp->GetModifyTime(szKey) : 0;
}
bool CBondContainer::GetCompanyInfoById(const std::string& szKey, int nID,
                                        REPORT& report) {
  if (nID < 0 || nID >= GetSize()) return false;
  memset(&report, 0, sizeof(report));
  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  return ptmp ? ptmp->GetCompanyRepByKey(szKey, report) : false;
}

bool CBondContainer::GetClentQuotByKey(const char* szBondKey, const char* szKey,
                                       BKQUOTE& stQuot) {
  int nId = 0;
  CBondInfo info;
  if (GetBondInfoByCombKey(szBondKey, &info, &nId)) {
    CBondBankRep* ptmp = GetClntRep(nId);
    if (ptmp && ptmp->GetBankRepByKey(szKey, stQuot)) {
      return true;
    }
  }
  return false;
}

time_t CBondContainer::GetCompanyTimeById(const std::string& szKey, int nID) {
  if (nID < 0 || nID >= GetSize()) return 0;

  time_t updtime = 0;
  REPORT stRep;
  memset(&stRep, 0, sizeof(stRep));
  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp) {
    ptmp->GetCompanyRepByKey(szKey, stRep);
    updtime = stRep.m_time > 0
                  ? stRep.m_time
                  : max(stRep.m_askinfo.m_time, stRep.m_bidinfo.m_time);
    return updtime;
  }

  return updtime;
}

bool CBondContainer::GetBilateralfoById(int nID) {
  class BilateralfoFinder : public CBondCompanyRep::ApplyCallback {
    bool m_found;

   public:
    bool operator()(CBondCompanyRep* ptmp) {
      m_found = false;
      if (ptmp) ptmp->ApplyAccess(true, "", this);
      return m_found;
    }
    virtual bool DoAccess(const REPORT& rpt) {
      if (0 == atoi(rpt.m_company_id)) return true;  // 去掉交易所cfets报价
      if (strcmp(rpt.m_bidinfo.m_price_status, "0") == 0 ||
          strcmp(rpt.m_askinfo.m_price_status, "0") == 0)
        return true;

      if (!IsEmpty(rpt.m_bidinfo.m_sPrice) &&
          !IsEmpty(rpt.m_askinfo.m_sPrice)) {
        m_found = true;
        return false;
      }
      return true;
    }
  };

  if (nID < 0 || nID >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    return BilateralfoFinder()(ptmp);
  }
  return false;
}

bool CBondContainer::IsBilateralfoById(const char* sCompanyID, int nID) {
  class BilateralfoFinder : public CBondCompanyRep::ApplyCallback {
    bool m_found;
    int m_brokerId;

   public:
    BilateralfoFinder(int brokerId) : m_brokerId(brokerId){};
    bool operator()(CBondCompanyRep* ptmp) {
      m_found = false;
      if (ptmp) ptmp->ApplyAccess(true, "", this);
      return m_found;
    }
    virtual bool DoAccess(const REPORT& rpt) {
      if (m_brokerId != atoi(rpt.m_company_id))
        return true;  // 去掉交易所cfets报价
      if (strcmp(rpt.m_bidinfo.m_price_status, "0") == 0 ||
          strcmp(rpt.m_askinfo.m_price_status, "0") == 0)
        return true;

      if (!IsEmpty(rpt.m_bidinfo.m_sPrice) &&
          !IsEmpty(rpt.m_askinfo.m_sPrice)) {
        m_found = true;
        return false;
      }
      return true;
    }
  };

  if (!sCompanyID || nID < 0 || nID >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    BilateralfoFinder finder(atoi(sCompanyID));
    return finder(ptmp);
  }
  return false;
}

bool CBondContainer::GetBilateralfoByIdOverSea(int nID) {
  class BilateralfoOverseaFinder : public CBondCompanyRep::ApplyCallback {
    bool m_found;

   public:
    bool operator()(CBondCompanyRep* ptmp) {
      m_found = false;
      if (ptmp) ptmp->ApplyAccess(true, "", this);
      return m_found;
    }
    virtual bool DoAccess(const REPORT& rpt) {
      if (rpt.m_price_sel == Indicative_Price) {
        if (strcmp(rpt.m_indx_info.m_symbol, "0") == 0 &&
            !IsEmpty(rpt.m_indx_info.m_price)) {
          m_found = true;
          return false;
        }
      }
      return true;
    }
  };

  if (nID < 0 || nID >= GetSize()) return false;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    return BilateralfoOverseaFinder()(ptmp);
  }
  return false;
}

bool CBondContainer::GetDiffenceById(const BLHCONDITION& Cond, int nID) {
  class GetDiffenceByIdCallback : public CBondCompanyRep::ApplyCallback {
    bool m_found;
    const char* m_diff_price;

   public:
    GetDiffenceByIdCallback(const char* diffPrice)
        : m_found(false), m_diff_price(diffPrice) {}
    bool IsFound() const { return m_found; }
    virtual bool DoAccess(const REPORT& quote) {
      if (strcmp(quote.m_bidinfo.m_sPrice, "Bid") == 0 ||
          strcmp(quote.m_askinfo.m_sPrice, "Ofr") == 0)
        m_found = true;
      if (atof(m_diff_price) >=
          ((atof(quote.m_bidinfo.m_sPrice) - atof(quote.m_askinfo.m_sPrice)) *
           100.00))
        m_found = true;
      return m_found ? false : true;
    }
  };

  if (nID < 0 || nID >= GetSize()) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    GetDiffenceByIdCallback accessor(Cond.sDiffPrice);
    ptmp->ApplyAccess(true, "", &accessor);
    return accessor.IsFound();
  }
  return false;
}

bool CBondContainer::GetBankInfoById(const std::string& szKey, int nID,
                                     BKQUOTE& quote) {
  if (nID < 0 || nID >= GetSize()) return false;
  memset(&quote, 0, sizeof(quote));
  CBondBankRep* ptmp = GetBankRep(nID);
  return ptmp ? ptmp->GetBankRepByKey(szKey, quote) : false;
}

void CBondContainer::ClearReport() {
  BrokerRepMng->ClearReport();
  BankClientRepMng->ClearReport();
  BankRepMng->ClearReport();

  WRITELOCK(m_mutex);
  ClearVersion();
}

void CBondContainer::ClearReportLiquidation(LiquidationClearBestPrc clrFlag) {
  HUGELOCK(m_mutex);
  int nSize = (int)m_vctbond.size();
  for (int i = 0; i < nSize; i++)  // BIGLOOP
  {
    // 后期按需分配内存，指针使用前需要进行判断
    CBondCompanyRep* cr = GetCompanyRep(i);
    if (cr) cr->ClearLiquidation(clrFlag);

    CBondBankRep* bnk = GetBankRep(i);
    if (bnk) bnk->Clear(clrFlag);

    CBondBankRep* clnt = GetClntRep(i);
    if (clnt) clnt->Clear(clrFlag);
  }
  ClearVersion(clrFlag);
}

void CBondContainer::ClearXCQuote() { XCQuoteRepMng->ClearReport(); }

void CBondContainer::ClearCFETSQuote() { CfetsRepMng->ClearReport(); }

void CBondContainer::ClearCFETSDealQuote() { CfetsDealRepMng->ClearReport(); }

void CBondContainer::SetFreezeReport(const char* szCompanyID, bool bFreeze) {
  class BkQuoteFreezeWriter : public CBondBankRep::ApplyCallback {
    bool m_freeze;

   public:
    BkQuoteFreezeWriter(bool freeze) : m_freeze(freeze) {}
    virtual bool DoModify(BKQUOTE& quote) {
      if (m_freeze)
        quote.m_Freeze = Freeze_Price;
      else
        quote.m_Freeze = Normal_Price;
      return false;
    }
  };

  // 冻结行情
  int nSize = (int)m_vctbond.size();
  for (int i = 0; i < nSize; i++)  // BIGLOOP
  {
    CBondBankRep* pRep = GetClntRep(i);
    if (pRep) {
      BkQuoteFreezeWriter writer(bFreeze);
      pRep->ApplyModify(false, szCompanyID, &writer);
    }
  }
}

bool CBondContainer::SetMap() {
  HUGELOCK(m_mutex);

  m_map.RemoveAll();
  m_keymap.RemoveAll();

  int size = GetSize();
  int hash_capcity = qb::base::GetHashPrimeLargerThan(m_vctbond.capacity());
  m_map.InitHashTable(hash_capcity);
  m_keymap.InitHashTable(hash_capcity);

  if (size == 0) return true;
  for (int i = 0; i < size; i++)  // BIGLOOP
  {
    const CBondInfo& info = ElementAtR(i);
    m_map.SetAt(info.GetCombBondCode(), (void*)(intptr_t)i);
    m_keymap.SetAt(info.GetCombBondKey(), (void*)(intptr_t)i);
  }
  return true;
}

bool CBondContainer::Clear() {
  BrokerRepMng->Clear();
  BankClientRepMng->Clear();
  BankRepMng->Clear();
  XCQuoteRepMng->Clear();
  CfetsRepMng->Clear();
  CfetsDealRepMng->Clear();

  HUGELOCK(m_mutex);

  for (int i = m_vctbond.size() - 1; i >= 0; --i)  // BIGLOOP
  {
    if (m_vctbond[i] != nullptr) {
      // delete m_vctbond[i];
      m_vctbond[i] = nullptr;
    }
  }
  m_vctbond.clear();

  // 增续发券相关信息
  for (int i = m_vctaddi.size() - 1; i >= 0; i--)  // BIGLOOP
  {
    if (m_vctaddi[i] != nullptr) {
      delete m_vctaddi[i];
      m_vctaddi[i] = nullptr;
    }
  }

  m_vctaddi.clear();
  m_mapaddi.clear();
  m_map.RemoveAll();
  m_keymap.RemoveAll();
  return true;
}

bool CBondContainer::Remove(const char* combBondKey, bool isAddition) {
  WRITELOCK(m_mutex);
  int nIndex = GetBondIndexImpl(combBondKey);
  if (nIndex >= 0 && nIndex < GetSizeImpl()) {
    CBondInfo& info = ElementAtW(nIndex);
    if (!isAddition) {
      // LOGDEBUG("[DICT]Not Additional Bond Dict");
      if (info.IsAddIssueBond()) {
        // LOGDEBUG("[DICT]Additional Bond, cannot Remove");
        return false;  // 非增续发字典删除时，判定：如果是增续发券，保留
      } else {
        // LOGDEBUG("[DICT]Not Additional Bond, Remove");
      }
    } else {
      // LOGDEBUG("[DICT]Additional Bond Dict, Remove");
    }
    // LOGDEBUG("[DICT]Removed");
    info.SetValidity(false);
    return true;
  }
  return false;
}
bool CBondContainer::Remove(const char* szKey, const char* szMarket,
                            bool isAddition) {
  WRITELOCK(m_mutex);
  int nIndex = GetBondIndex(szKey, szMarket);
  if (nIndex >= 0 && nIndex < GetSizeImpl()) {
    CBondInfo& info = ElementAtW(nIndex);
    if (!isAddition) {
      // LOGDEBUG("[DICT]Not Additional Bond Dict");
      if (info.IsAddIssueBond()) {
        // LOGDEBUG("[DICT]Additional Bond, cannot Remove");
        return false;  // 非增续发字典删除时，判定：如果是增续发券，保留
      } else {
        // LOGDEBUG("[DICT]Not Additional Bond, Remove");
      }
    } else {
      // LOGDEBUG("[DICT]Additional Bond Dict, Remove");
    }
    // LOGDEBUG("[DICT]Removed");
    info.SetValidity(false);
    return true;
  }
  return false;
}

void CBondContainer::ClearCDCDataAll() {
  CBondCDCPriceInfo::instance().ClearAll();
}

void CBondContainer::ClearCDCData(bool bSpecial) {
  if (bSpecial)
    CBondCDCPriceInfo::instance().ClearSpecial();
  else
    CBondCDCPriceInfo::instance().ClearNonSpecial();
}

void CBondContainer::ClearCSData() { CBondCSInfo::instance().clear(); }

void CBondContainer::CalcRemainingDate(time_t t) {
  static std::mutex s_lock;
  bool isFirst = false;
  {
    std::lock_guard<std::mutex> m_locker(s_lock);
    isFirst = m_nLastCalcDate == 0;
    int lastCalcDate = 0;
    struct tm* tt = localtime(&t);
    if (tt)
      lastCalcDate =
          (tt->tm_year + 1900) * 10000 + (tt->tm_mon + 1) * 100 + tt->tm_mday;
    if (lastCalcDate == m_nLastCalcDate) return;
    m_nLastCalcDate = lastCalcDate;
  }

  // MEM_METRIC("CalcRemainingDate");
  log_begin();
  {
    using qb::base::os::fmtstr;
    std::vector<int> abonds, absBonds;
    int nPass = 0, nSecond = 0, nSize = 0;
    const char* expired_str = strBondLib_Expired(); /*"已到期"*/ /*"已到期"*/
    {
      HUGELOCK(m_mutex);
      nSize = GetSize();
      abonds.reserve(nSize);
      absBonds.reserve(nSize);

      int Today = 0;
      if (t > 0) {
        struct tm* tmNow = localtime(&t);
        Today = (tmNow->tm_year + 1900) * 10000 + (tmNow->tm_mon + 1) * 100 +
                tmNow->tm_mday;
      }
      for (int i = 0; i < nSize; i++)  // BIGLOOP
      {
        CBondInfo& info = ElementAtW(i);
        if (info.IsValidBond()) {
          /*	原先逻辑是:对所有有效债券(非空的BondKey),重新计算其剩余期限字段(两个)
                  现在更改为:只针对未过期的债券,才重新计算器剩余期限字段(两个)
                  对于已经过期的券,CBondInfoDebug::GetRemainPeriod中返回过期字符串
           */
          if (strcmp(expired_str, info.GetRemainPeriodByIntTime(Today)) != 0) {
            // 之前计算没有过期,现在按照现在时间,再来计算看是否过期
            if (!isFirst) info.SetRemainDate("");
            if (isFirst || strcmp(expired_str,
                                  info.GetRemainPeriodByIntTime(Today)) != 0) {
              nSecond++;
              abonds.push_back(i);
              if (!info.IsExchange() && info.IsBondABS()) absBonds.push_back(i);
            } else {
              nPass++;
            }
          } else {
            nPass++;
          }
        }
      }
    }
    // timer.AddStep(fmtstr("总数量:%6d 过期:%6d 二次计算:%6d", nSize, nPass,
    // nSecond));

    int absCount = absBonds.size();
    std::vector<int> abondsCopy = abonds;
    // timer.AddStep("拷贝vector<int>");

    CSSVContainer::availableBond().SetDataSafe(std::move(abonds));
    CSSVContainer::availableAbsBond().SetDataSafe(std::move(absBonds));

    // 更新交易所有效债券
    std::vector<int> exBonds;
    exBonds.reserve(abondsCopy.size());
    for (int i = 0; i < (int)abondsCopy.size(); ++i) {
      if (ElementAtR(abondsCopy[i]).IsExchange())
        exBonds.push_back(abondsCopy[i]);
    }
    int exCount = exBonds.size();
    CSSVContainer::availableExBond().SetDataSafe(std::move(exBonds));
    // timer.AddStep(fmtstr("更新AfxGetExchangeBond:%d", exCount));
  }
  log_end();
  DumpStatus();
}

void CBondContainer::CalcBondExpireInHoliday() {
  CBondCalendar& cal = CBondCalendar::instance();
  HUGELOCK(m_mutex);
  int nSize = GetSize();
  for (int i = 0; i < nSize; i++)  // BIGLOOP
  {
    CBondInfo& info = ElementAtW(i);
    if (info.IsValidBond() &&
        strcmp(info.GetRemainDate(), strBondLib_Expired() /*"已到期"*/) != 0) {
      int nDate = atoi(info.GetMaturityDate());
      if (cal.IsHoliday("CNY", "CIB", nDate))
        info.SetExpireInHoliday(true);
      else if (cal.IsHoliday("CNY", "SSE", nDate))
        info.SetExpireInHoliday(true);
      else
        info.SetExpireInHoliday(false);
    }
  }
}

int CBondContainer::GetLastCalcDate() { return m_nLastCalcDate; }

double CBondContainer::CalcRemainingDay(const std::string& period, bool ytm) {
  const char* sPeriod = period.c_str();
  if (sPeriod == 0 || *sPeriod == '\0') return -1;
  // 原始逻辑
  // 截取+之前的部分,如果没有,取整个部分
  // 将末尾的空白字符移除
  // 取末尾字符为YMD
  // 将开头字符串转化为整数
  // 格式: \d+[YMD]\s*\+?
  // 性能测试结果:优化编译12-15倍,不优化编译7倍
  // 性能和单元测试见本路径的CalcRemainingDay_UnitTest.cpp,
  // 测试工程见QBBrowser\UnitTest\UnitTest.vcxproj
  // 实现需要使用CalcRemainingDay_UnitTest.cpp中的RemainingDayCollector收集采样数据
  static double ten[8] = {1,      0.1,     0.01,     0.001,
                          0.0001, 0.00001, 0.000001, 0.0000001};
  const char* pstr = sPeriod;  //
  double result = INVALID_CDC_VALUE;
  auto is_plus = [](const char schar) { return schar == '+'; };
  int round = ytm ? (std::count_if(period.begin(), period.end(), is_plus)) : 0;
  if (round < 0) round = 0;
  for (auto roundNum = 0; roundNum <= round; ++roundNum) {
    if (*pstr == '\0') break;
    int num1 = 0, num2 = 0;
    int num_count = 0;  // 开头是数字的个数
    int bit = 0;
    bool dot = false;
    bool num_mode = true;  // 开始必须是数字模式
    int ncount = 0;        // 设定单位之后出现非blank的字符串个数
    char unit = 0;         // 必须设定
    while (*pstr != '\0' && *pstr != '+') {
      char c = *pstr++;
      if (num_mode) {
        if ((c >= '0' && c <= '9') || c == '.') {
          if (c == '.')
            dot = true;
          else if (!dot)
            num1 = (num1 << 3) + (num1 << 1) + (c - '0');
          else {
            num2 = (num2 << 3) + (num2 << 1) + (c - '0');
            bit++;
          }
          num_count++;
        } else if (num_count <= 0)
          break;
        else
          num_mode = false;
      }
      if (!num_mode) {
        if (c == 'Y' || c == 'M' || c == 'D') {
          unit = c;
          ncount = 0;
        } else if (c != ' ') {
          unit = 0;
          ncount++;
        }
      }
    }

    if (num_count > 0 && unit != 0 && ncount <= 0) {
      double u = (unit == 'Y') ? 365 : (unit == 'M' ? 30.01 : 1);
      double dTmp =
          bit < 8 ? (u * (num1 + num2 * ten[bit])) : atof(sPeriod) * u;
      result = (result == INVALID_CDC_VALUE) ? dTmp : result + dTmp;
    }
    if (!ytm) break;       // 如果未到期
    while (*pstr != '\0')  // 去除加号和空格
    {
      char c = *pstr;
      if ((c >= '0' && c <= '9') || c == '.') {
        break;
      }
      pstr++;
    }
  }

  return (result == INVALID_CDC_VALUE) ? -999 : result;
}

bool CBondContainer::UpdateContainerByExchange(
    BLHCONDITION& condStr, SSBrokerKeyVector& vct_result,
    SSBrokerKeyVector& vct_resdel, const std::list<xQBBestPriceUnit_c>& qblist,
    bool bSecondaryMarket) {
  // 底层会改写condStr的sCompanyid字段,因此condStr不能是const
  READLOCK(m_mutex);
  if (condStr.isAllin()) {
    std::list<xQBBestPriceUnit_c>::const_iterator itor = qblist.begin();
    for (; itor != qblist.end(); itor++) {
      bool bAdd = false, bGiveup = false;
      BrokerKey brokerkey;
      int bondIndex = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
      if (!IsValidIndex(bondIndex)) continue;
      brokerkey.m_nIndex = bondIndex;
      brokerkey.SetBrokerId(itor->m_company_id);

      if (strcmp(itor->m_price_status, "0") == 0) {
        vct_resdel.m_vct.push_back(brokerkey);
      } else if (bAdd) {
        vct_result.m_vct.push_back(brokerkey);
      } else {
        bGiveup = true;
      }

      if (!bGiveup)
        NETLOG("%s has been pushed --> %s, ver = %d", itor->m_bond_shorname,
               bAdd ? "vct_result" : "vct_resdel", itor->m_version);
      else
        NETLOG("%s has been gived up, ver = %d", itor->m_bond_shorname,
               itor->m_version);
    }
  } else {
    bool HasRatingRightsOfCDC =
        true;  // AfxGetUserAccountManager().HasAuthOfCDC();
    bool HasRatingRightsOfCSI =
        true;  // AfxGetUserAccountManager().HasAuthOfCSI();
    bool HasRatingRightsOfCBR =
        true;  // AfxGetUserAccountManager().HasAuthOfCBR();

    BrokerKey brokerkey;
    int nCount = 0;
    std::list<xQBBestPriceUnit_c>::const_iterator itor = qblist.begin();
    for (; itor != qblist.end(); itor++) {
      int bondIndex = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
      if (!IsValidIndex(bondIndex)) continue;
      const CBondInfo& info = ElementAtR(bondIndex);

      brokerkey.Clear();
      FIELDCOPY(condStr.sCompanyid,
                itor->m_company_id);  // 用自身的brokerid过滤，20150901
      bool bContinue = false;
      do {
        if (condStr.nBothFlg != 0 && !IsHasPrice(condStr, bondIndex, BothValid))
          break;
        if (condStr.nNewFlg != 0 && !info.IsNewBond()) break;
        if (condStr.nHasFlg != 0 && !IsHasPrice(condStr, bondIndex)) break;
        if (condStr.nMatFlg != 0 && GetMaturityBond(info)) break;
        if (condStr.nASemi != 0 && GetRebateBond(info)) break;
        if (condStr.nMortgt != 0 && !info.IsMortgage()) break;
        if (condStr.nCrosmk != 0 && !info.IsCrossMarket()) break;
        if (condStr.nEntrTyp != 0 && !GetSOEenterType(condStr, info)) break;
        if (condStr.nOffset != 0 && !GetBondOffsetEstPrc(condStr, bondIndex))
          break;
        if (condStr.nSettlement[0] != CBondContainer::StmAll &&
            !CheckSettlement(condStr, bondIndex))
          break;
        if (!IsEmpty(condStr.sDiffPrice) && !GetDiffPrice(condStr, bondIndex))
          break;
        if ((!IsEmpty(condStr.sBPrice) || !IsEmpty(condStr.sBPriceEnd)) &&
            !CheckBidPrice(condStr, bondIndex))
          break;
        if ((!IsEmpty(condStr.sOPrice) || !IsEmpty(condStr.sOPriceEnd)) &&
            !CheckOfrPrice(condStr, bondIndex))
          break;
        if ((!IsEmpty(condStr.sOPrice) || !IsEmpty(condStr.sOPriceEnd)) &&
            !CheckOfrPrice(condStr, bondIndex))
          break;
        if (condStr.nCommonUse[0] != CBondContainer::CommAll &&
            !info.CheckCommonUseType(condStr))  // 常用
          break;
        if (condStr.nTypeNew[0] != newBondAll &&
            !info.CheckBondTypeNew(condStr))
          break;
        if (condStr.nIssuerRating[0] != RatingAll &&
            !GetMultiLevel(condStr, info))
          break;
        if (condStr.nOutlookRating[0] != OutlookRatingAll &&
            !GetOutlookRatingLevel(condStr, info))
          break;
        if (HasRatingRightsOfCDC && condStr.nCDCRating[0] != CDCRatingAll &&
            !GetCDCRatingLevel(condStr, info))
          break;
        if (HasRatingRightsOfCSI && condStr.nCSIRating[0] != CSIRatingAll &&
            !GetCSIRatingLevel(condStr, info))
          break;
        if (HasRatingRightsOfCBR && condStr.nCBRRating[0] != CBRRatingAll &&
            !GetCBRRatingLevel(condStr, info))
          break;
        if (condStr.nWarrant[0] != WarrAll && !GetWarrType(condStr, info))
          break;
        if (condStr.nCouponType[0] != CouponAll &&
            !GetMultiCouponType(condStr, info))
          break;
        if (condStr.nRight != RightAll &&
            GetRightType(condStr.nRight) != info.IsRight())
          break;
        if (condStr.nRightEx[0] != RightExAll && !info.CheckRightEx(condStr))
          break;
        if (condStr.nRange[0] != RangeAll &&
            !GetMaturityRange(condStr, info, bSecondaryMarket))
          break;
        if (condStr.nMunicp[0] != MunicAll && !GetMunicpType(condStr, info))
          break;
        if (condStr.nInterbank != 0 && !info.IsInterbank()) break;
        if (condStr.nExchange != 0 && !info.IsExchange()) break;
        if (condStr.nInstion[0] != InstAll && !GetMultiInstion(condStr, info))
          break;
        if (condStr.szIssuer[0][0] != '\0' && !info.CheckIssuer(condStr)) break;
        if (condStr.szGuarantor[0][0] != '\0' && !info.CheckGuarantor(condStr))
          break;
        if (condStr.szSector[0][0] != '\0' && !info.CheckSector(condStr)) break;
        if (condStr.szSector2021[0][0] != '\0' &&
            !info.CheckSector2021(condStr))
          break;
        if (condStr.szArea[0][0] != '\0' && !info.CheckArea(condStr)) break;
        if (condStr.szSubType[0][0] != '\0' && !info.CheckBontSubType(condStr))
          break;
        if (condStr.nDebtRating[0] != DRatingNone &&
            !info.CheckDebtRating(condStr))
          break;
        if (condStr.nFinDebt[0] != FinDebtNone && !info.CheckFinDebt(condStr))
          break;
        if (condStr.nPlatform[0] != PlatforamAll &&
            !IsPlatformType(condStr, info))  // 平台债
          break;
        if (condStr.nLocalBond[0] != LocalBondAll &&
            !IsLocalBond(condStr, info))  // 地方债
          break;
        if (condStr.nNCDRating[0] != NCDRatingAll &&
            !info.CheckNCDRating(condStr))  // NCD , add  by lbl  NCD
          break;
        if (condStr.nIssueYear[0] != 0 &&
            !info.CheckIssueYear(condStr))  // 发行年份
          break;
        if (!IsEmpty(condStr.sVolBid) &&
            !GetVolBidCompare(condStr, bondIndex))  // vol.bid
          break;
        if (!IsEmpty(condStr.sVolOfr) &&
            !GetVolOfrCompare(condStr, bondIndex))  // vol.ofr
          break;
        if (condStr.nListedPlace[0] != CBondContainer::kExchAll &&
            !GetExchangeType(condStr, info))  // 交易所类型
          break;
        if (condStr.nETSBond[0] != CBondContainer::ETSBondAll &&
            !IsETSBondType(condStr, info))  // 永续债
          break;
        if (condStr.nCorpBond[0] != CBondContainer::CorpBondAll &&
            !IsCorpBondType(condStr, info))  // 公司债
          break;
        if (condStr.nAssetStatus[0] != CBondContainer::AssetAll &&
            !info.CheckAssetStatus(condStr))  // 发行
          break;
        if (!IsEmpty(condStr.sBidCdc) &&
            !GetBidCdcCompare(condStr, bondIndex))  // bid-中债
          break;
        if (!IsEmpty(condStr.sCdcOfr) &&
            !GetCdcOfrCompare(condStr, bondIndex))  // 中债-ofr
          break;
        if (condStr.nExpireInHoliday == 1 &&
            info.IsExpireInHoliday())  // 不含假期
          break;
        bContinue = true;
      } while (0);
      brokerkey.m_nIndex = bondIndex;
      brokerkey.SetBrokerId(itor->m_company_id);

      if (!bContinue)
        vct_resdel.m_vct.push_back(brokerkey);
      else
        vct_result.m_vct.push_back(brokerkey);

      NETLOG("%s has been pushed --> vct_result, ver = %d",
             itor->m_bond_shorname, bContinue ? "vct_result" : "vct_resdel",
             itor->m_version);
    }
  }

  return true;
}

bool CBondContainer::UpdateContainerBySSEFI(
    BLHCONDITION& condStr, SSBrokerKeyVector& vct_result,
    SSBrokerKeyVector& vct_resdel, const std::list<xQBBestPriceUnit_c>& qblist,
    bool bSecondaryMarket) {
  // 底层会改写condStr的sCompanyid字段,因此condStr不能是const
  READLOCK(m_mutex);

  BrokerKey brokerkey;
  int nCount = 0;
  std::list<xQBBestPriceUnit_c>::const_iterator itor = qblist.begin();
  for (; itor != qblist.end(); itor++) {
    int bondIndex = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
    if (!IsValidIndex(bondIndex)) continue;

    brokerkey.Clear();
    const CBondInfo& info = ElementAtR(bondIndex);
    if (strcmp(info.GetListedMarket(), "SSE") != 0) continue;
    FIELDCOPY(condStr.sCompanyid,
              itor->m_company_id);  // 用自身的brokerid过滤，20150901
    bool bContinue = false;
    do {
      if (condStr.nBothFlg != 0 && !IsHasPrice(condStr, bondIndex, BothValid))
        break;
      if (condStr.nNewFlg != 0 && !info.IsNewBond()) break;
      if (condStr.nHasFlg != 0 && !IsHasPrice(condStr, bondIndex)) break;
      if (condStr.nMatFlg != 0 && GetMaturityBond(info)) break;
      if (condStr.nASemi != 0 && GetRebateBond(info)) break;
      if (condStr.nMortgt != 0 && !info.IsMortgage()) break;
      if (condStr.nCrosmk != 0 && !info.IsCrossMarket()) break;
      if (condStr.nEntrTyp != 0 && !GetSOEenterType(condStr, info)) break;
      if (condStr.nOffset != 0 && !GetBondOffsetEstPrc(condStr, bondIndex))
        break;
      if (!IsEmpty(condStr.sDiffPrice) && !GetDiffPrice(condStr, bondIndex))
        break;
      if (!IsEmpty(condStr.sBPrice) && !CheckBidPrice(condStr, bondIndex))
        break;
      if (condStr.nCommonUse[0] != CBondContainer::CommAll &&
          !info.CheckCommonUseType(condStr))  // 常用
        break;
      if (!IsEmpty(condStr.sOPrice) && !CheckOfrPrice(condStr, bondIndex))
        break;
      if (condStr.nIssuerRating[0] != RatingAll &&
          !GetMultiLevel(condStr, info))
        break;
      if (condStr.nWarrant[0] != WarrAll && !GetWarrType(condStr, info)) break;
      if (condStr.nCouponType[0] != CouponAll &&
          !GetMultiCouponType(condStr, info))
        break;
      if (condStr.nRight != RightAll &&
          GetRightType(condStr.nRight) != info.IsRight())
        break;
      if (condStr.nRightEx[0] != RightExAll && !info.CheckRightEx(condStr))
        break;
      if (condStr.nRange[0] != RangeAll &&
          !GetMaturityRange(condStr, info, bSecondaryMarket))
        break;
      if (condStr.nMunicp[0] != MunicAll && !GetMunicpType(condStr, info))
        break;
      if (condStr.nInterbank != 0 && !info.IsInterbank()) break;
      if (condStr.nExchange != 0 && !info.IsExchange()) break;
      if (condStr.nInstion[0] != InstAll && !GetMultiInstion(condStr, info))
        break;
      if (condStr.szIssuer[0][0] != '\0' && !info.CheckIssuer(condStr)) break;
      if (condStr.szSector[0][0] != '\0' && !info.CheckSector(condStr)) break;
      if (condStr.szSector2021[0][0] != '\0' && !info.CheckSector2021(condStr))
        break;
      if (condStr.szArea[0][0] != '\0' && !info.CheckArea(condStr)) break;
      if (condStr.szSubType[0][0] != '\0' && !info.CheckBontSubType(condStr))
        break;
      if (condStr.nDebtRating[0] != DRatingNone &&
          !info.CheckDebtRating(condStr))
        break;
      if (condStr.nFinDebt[0] != FinDebtNone && !info.CheckFinDebt(condStr))
        break;
      if (condStr.nPlatform[0] != PlatforamAll &&
          !IsPlatformType(condStr, info))  // 平台债
        break;
      if (condStr.nLocalBond[0] != LocalBondAll &&
          !IsLocalBond(condStr, info))  // 地方债
        break;
      if (condStr.nNCDRating[0] != NCDRatingAll &&
          !info.CheckNCDRating(condStr))  // add  by lbl  NCD
        break;
      if (condStr.nIssueYear[0] != 0 && !info.CheckIssueYear(condStr)) break;
      if (!IsEmpty(condStr.sVolBid) &&
          !GetVolBidCompare(condStr, bondIndex))  // vol.bid
        break;
      if (!IsEmpty(condStr.sVolOfr) &&
          !GetVolOfrCompare(condStr, bondIndex))  // vol.ofr
        break;
      if (condStr.nListedPlace[0] != CBondContainer::kExchAll &&
          !GetExchangeType(condStr, info))  // 交易所类型
        break;
      if (condStr.nETSBond[0] != CBondContainer::ETSBondAll &&
          !IsETSBondType(condStr, info))  // 永续债
        break;
      if (condStr.nCorpBond[0] != CBondContainer::CorpBondAll &&
          !IsCorpBondType(condStr, info))  // 公司债
        break;
      if (condStr.nAssetStatus[0] != CBondContainer::AssetAll &&
          !info.CheckAssetStatus(condStr))  // 发行
        break;
      if (!IsEmpty(condStr.sBidCdc) &&
          !GetBidCdcCompare(condStr, bondIndex))  // bid-中债
        break;
      if (!IsEmpty(condStr.sCdcOfr) &&
          !GetCdcOfrCompare(condStr, bondIndex))  // 中债-ofr
        break;
      if (condStr.nExpireInHoliday == 1 &&
          info.IsExpireInHoliday())  // 不含假期
        break;
      bContinue = true;
    } while (0);
    brokerkey.m_nIndex = bondIndex;
    brokerkey.SetBrokerId(itor->m_company_id);

    if (!bContinue) {
      vct_resdel.m_vct.push_back(brokerkey);
    } else {
      vct_result.m_vct.push_back(brokerkey);
    }
    NETLOG("%s has been pushed --> vct_result, ver = %d", itor->m_bond_shorname,
           bContinue ? "vct_result" : "vct_resdel", itor->m_version);
  }

  return true;
}

bool CBondContainer::UpdateContainerByABSBond(
    BLHCONDITION& condStr, SSBrokerKeyVector& vct_result,
    SSBrokerKeyVector& vct_resdel, const std::list<xQBBestPriceUnit_c>& qblist,
    bool bSecondaryMarket) {
  return true;
}

bool CBondContainer::UpdateOverSeaContainer(
    const BLHCONDITION& condStr, SSBrokerKeyVector& vct_result,
    SSBrokerKeyVector& vct_resdel,
    const std::list<xQBIndicativePriceUnit_c>& qblist, bool bSecondaryMarket) {
  READLOCK(m_mutex);
  if (condStr.isAllin()) {
    std::list<xQBIndicativePriceUnit_c>::const_iterator itor = qblist.begin();
    for (; itor != qblist.end(); itor++) {
      bool bAdd = false;
      BrokerKey brokerkey;
      int bondIndex = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
      brokerkey.m_nIndex = bondIndex;
      brokerkey.SetBrokerId(itor->m_company_id);
      if (IsEmpty(itor->m_price))
        vct_resdel.m_vct.push_back(brokerkey);
      else if (bAdd)
        vct_result.m_vct.push_back(brokerkey);
    }
  } else {
    BrokerKey brokerkey;
    int nCount = 0;
    std::list<xQBIndicativePriceUnit_c>::const_iterator itor = qblist.begin();
    for (; itor != qblist.end(); itor++) {
      int bondIndex = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
      if (!IsValidIndex(bondIndex)) continue;
      const CBondInfo& info = ElementAtR(bondIndex);

      bool bContinue = true;
      brokerkey.Clear();

      if (bContinue && condStr.nBothFlg != 0 &&
          !IsHasPrice(condStr, bondIndex, BothValid))
        bContinue = false;
      if (bContinue && condStr.nNewFlg != 0 && !info.IsNewBond())
        bContinue = false;
      if (bContinue && condStr.nHasFlg != 0 && !IsHasPrice(condStr, bondIndex))
        bContinue = false;
      if (bContinue && condStr.nMatFlg != 0 && GetMaturityBond(info))
        bContinue = false;
      if (bContinue && condStr.nASemi != 0 && GetRebateBond(info))
        bContinue = false;
      if (bContinue && condStr.nMortgt != 0 && !info.IsMortgage())
        bContinue = false;
      if (bContinue && condStr.nCrosmk != 0 && !info.IsCrossMarket())
        bContinue = false;
      if (bContinue && condStr.nEntrTyp != 0 && !GetSOEenterType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nOffset != 0 &&
          !GetBondOffsetEstPrc(condStr, bondIndex))
        bContinue = false;
      if (bContinue && !IsEmpty(condStr.sDiffPrice) &&
          !GetDiffPrice(condStr, bondIndex))
        bContinue = false;
      if (bContinue &&
          (!IsEmpty(condStr.sBPrice) || !IsEmpty(condStr.sBPriceEnd)) &&
          !CheckBidPrice(condStr, bondIndex))
        bContinue = false;
      if (bContinue &&
          (!IsEmpty(condStr.sOPrice) || !IsEmpty(condStr.sOPriceEnd)) &&
          !CheckOfrPrice(condStr, bondIndex))
        bContinue = false;
      if (bContinue && condStr.nCommonUse[0] != CBondContainer::CommAll &&
          !info.CheckCommonUseType(condStr))  // 常用
        bContinue = false;
      if (bContinue && condStr.nTypeNew[0] != newBondAll &&
          !info.CheckBondTypeNew(condStr))
        bContinue = false;
      if (bContinue && condStr.nIssuerRating[0] != RatingAll &&
          !GetMultiLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nOutlookRating[0] != OutlookRatingAll &&
          !GetOutlookRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nCDCRating[0] != CDCRatingAll &&
          !GetCDCRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCSIRating[0] != CSIRatingAll &&
          !GetCSIRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCBRRating[0] != CBRRatingAll &&
          !GetCBRRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nWarrant[0] != WarrAll &&
          !GetWarrType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCouponType[0] != CouponAll &&
          !GetMultiCouponType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nRight != RightAll &&
          GetRightType(condStr.nRight) != info.IsRight())
        bContinue = false;
      if (bContinue && condStr.nRange[0] != RangeAll &&
          !GetMaturityRange(condStr, info, bSecondaryMarket))
        bContinue = false;
      if (bContinue && condStr.nMunicp[0] != MunicAll &&
          !GetMunicpType(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nInterbank != 0 && !info.IsInterbank())
        bContinue = false;
      if (bContinue && condStr.nExchange != 0 && !info.IsExchange())
        bContinue = false;
      if (bContinue && condStr.nInstion[0] != InstAll &&
          !GetMultiInstion(condStr, info))
        bContinue = false;
      if (bContinue && condStr.szIssuer[0][0] != '\0' &&
          !info.CheckIssuer(condStr))
        bContinue = false;
      if (bContinue && condStr.szSector[0][0] != '\0' &&
          !info.CheckSector(condStr))
        bContinue = false;
      if (bContinue && condStr.szSector2021[0][0] != '\0' &&
          !info.CheckSector2021(condStr))
        bContinue = false;
      if (bContinue && condStr.szArea[0][0] != '\0' && !info.CheckArea(condStr))
        bContinue = false;
      if (bContinue && condStr.szSubType[0][0] != '\0' &&
          !info.CheckBontSubType(condStr))
        bContinue = false;
      if (bContinue && condStr.nDebtRating[0] != DRatingNone &&
          !info.CheckDebtRating(condStr))
        bContinue = false;
      if (bContinue && condStr.nFinDebt[0] != FinDebtNone &&
          !info.CheckFinDebt(condStr))
        bContinue = false;
      if (bContinue && condStr.nPlatform[0] != PlatforamAll &&
          !IsPlatformType(condStr, info))  // 平台债
        bContinue = false;
      if (bContinue && condStr.nLocalBond[0] != LocalBondAll &&
          !IsLocalBond(condStr, info))  // 地方债
        bContinue = false;
      // add  by lbl  NCD
      if (bContinue && condStr.nNCDRating[0] != NCDRatingAll &&
          !info.CheckNCDRating(condStr))  // NCD
        bContinue = false;
      // end
      if (bContinue && condStr.nIssueYear[0] != 0 &&
          !info.CheckIssueYear(condStr))
        bContinue = false;
      if (bContinue && condStr.nExpireInHoliday == 1 &&
          info.IsExpireInHoliday())  // 不含假期
        bContinue = false;
      brokerkey.m_nIndex = bondIndex;
      brokerkey.SetBrokerId(itor->m_company_id);
      if (/*IsEmpty(itor->m_price) && condStr.nHasFlg != 0 ||*/ !bContinue)
        vct_resdel.m_vct.push_back(brokerkey);
      else if (bContinue)
        vct_result.m_vct.push_back(brokerkey);
    }
  }

  return true;
}

bool CBondContainer::UpdateContainerByCFETS(
    const BLHCONDITION& condStr, SSBrokerKeyVector& vct_result,
    SSBrokerKeyVector& vct_resdel, const std::list<xQBBestPriceUnit_c>& qblist,
    bool bSecondaryMarket) {
  // 底层会改写condStr的sCompanyid字段,因此condStr不能是const
  if (condStr.nCFETSQuoteType < 0 || condStr.nCFETSQuoteType > 2) return false;
  if (strcmp(condStr.sCompanyid, "50") != 0) return false;

  READLOCK(m_mutex);

  BrokerKey brokerkey;
  int nCount = 0;
  char sType[16] = {0};
  std::list<xQBBestPriceUnit_c>::const_iterator itor = qblist.begin();
  for (; itor != qblist.end(); itor++) {
    int idx = GetBondIndex(itor->m_bondkey, itor->m_listedmarket);
    if (idx < 0) continue;
    const CBondInfo& info = ElementAtR(idx);
    bool bIsCDCAuthValid = info.IsCDCAuthValid();

    bool bGood = false;
    do {
      if (/*condStr.nExchange != 0 && */ info.IsExchange())  // 交易所债券不显示
        break;
      if (info.IsAddIssueBond()) break;  // 增续发
      if (condStr.nHasFlg != 0 && !IsCFETSHasPrice(condStr, idx)) break;
      if (condStr.nBothFlg != 0 && !IsCFETSBilateralPrice(condStr, idx)) break;
      if (condStr.nSettlement[0] != CBondContainer::StmAll &&
          !CheckCFETSSettlement(condStr, idx))  // 清算速度
        break;
      if (condStr.nNewFlg != 0 && !info.IsNewBond()) break;
      if (condStr.nMatFlg != 0 && GetMaturityBond(info)) break;
      if (condStr.nASemi != 0 && GetRebateBond(info)) break;
      if (condStr.nMortgt != 0 && !info.IsMortgage()) break;
      if (condStr.nCrosmk != 0 && !info.IsCrossMarket()) break;
      if (condStr.nEntrTyp != 0 && !GetSOEenterType(condStr, info)) break;
      if (!IsEmpty(condStr.sDiffPrice) && !GetCFETSDiffPrice(condStr, idx))
        break;
      if ((!IsEmpty(condStr.sBPrice) || !IsEmpty(condStr.sBPriceEnd)) &&
          !GetCFETSBidCndPrice(condStr, idx))
        break;
      if ((!IsEmpty(condStr.sOPrice) || !IsEmpty(condStr.sOPriceEnd)) &&
          !GetCFETSOfrCndPrice(condStr, idx))
        break;
      if (condStr.nCommonUse[0] != CBondContainer::CommAll &&
          !info.CheckCommonUseType(condStr))  // 常用
        break;
      if (condStr.nTypeNew[0] != newBondAll && !info.CheckBondTypeNew(condStr))
        break;
      if (condStr.nIssuerRating[0] != RatingAll &&
          !GetMultiLevel(condStr, info))
        break;
      if (condStr.nOutlookRating[0] != OutlookRatingAll &&
          !GetOutlookRatingLevel(condStr, info))
        break;
      if (condStr.nCDCRating[0] != CBondContainer::CDCRatingAll &&
          !GetCDCRatingLevel(condStr, info))  // 中债隐含
        break;
      if (condStr.nCSIRating[0] != CBondContainer::CSIRatingAll &&
          !GetCSIRatingLevel(condStr, info))  // 中证隐含
        break;
      if (condStr.nCBRRating[0] != CBondContainer::CBRRatingAll &&
          !GetCBRRatingLevel(condStr, info))  // 中债资信
        break;
      if (condStr.nWarrant[0] != WarrAll && !GetWarrType(condStr, info)) break;
      if (condStr.nCouponType[0] != CouponAll &&
          !GetMultiCouponType(condStr, info))
        break;
      if (condStr.nRight != RightAll &&
          GetRightType(condStr.nRight) != info.IsRight())
        break;
      if (condStr.nRightEx[0] != RightExAll && !info.CheckRightEx(condStr))
        break;
      if (condStr.nRange[0] != RangeAll &&
          !GetMaturityRange(condStr, info, bSecondaryMarket))
        break;
      if (condStr.nMunicp[0] != MunicAll && !GetMunicpType(condStr, info))
        break;
      if (condStr.nInstion[0] != InstAll && !GetMultiInstion(condStr, info))
        break;
      if (condStr.szIssuer[0][0] != '\0' && !info.CheckIssuer(condStr)) break;
      if (condStr.szSector[0][0] != '\0' && !info.CheckSector(condStr)) break;
      if (condStr.szSector2021[0][0] != '\0' && !info.CheckSector2021(condStr))
        break;
      if (condStr.szArea[0][0] != '\0' && !info.CheckArea(condStr)) break;
      if (condStr.szSubType[0][0] != '\0' && !info.CheckBontSubType(condStr))
        break;
      if (condStr.nDebtRating[0] != DRatingNone &&
          !info.CheckDebtRating(condStr))
        break;
      if (condStr.nFinDebt[0] != FinDebtNone && !info.CheckFinDebt(condStr))
        break;
      if (condStr.nPlatform[0] != CBondContainer::PlatforamAll &&
          !IsPlatformType(condStr, info))  // 平台债
        break;
      if (condStr.nLocalBond[0] != CBondContainer::LocalBondAll &&
          !IsLocalBond(condStr, info))  // 地方债
        break;
      if (condStr.nNCDRating[0] != NCDRatingAll &&
          !info.CheckNCDRating(condStr))  // add  by lbl  NCD
        break;
      if (condStr.nIssueYear[0] != 0 && !info.CheckIssueYear(condStr)) break;
      if (condStr.nETSBond[0] != CBondContainer::ETSBondAll &&
          !IsETSBondType(condStr, info))  // 永续债
        break;
      if (condStr.nCorpBond[0] != CBondContainer::CorpBondAll &&
          !IsCorpBondType(condStr, info))  // 公司债
        break;
      if (condStr.nAssetStatus[0] != CBondContainer::AssetAll &&
          !info.CheckAssetStatus(condStr))  // 发行
        break;
      if (!IsEmpty(condStr.sBidCdc) &&
          !GetCFETSBidCdcCompare(condStr, idx, bIsCDCAuthValid))  // bid-中债
        break;
      if (!IsEmpty(condStr.sCdcOfr) &&
          !GetCFETSCdcOfrCompare(condStr, idx, bIsCDCAuthValid))  // 中债-ofr
        break;
      if (!IsEmpty(condStr.sVolBid) &&
          !GetCFETSBidVol(condStr, idx))  // bid.vol
        break;
      if (!IsEmpty(condStr.sVolOfr) &&
          !GetCFETSOfrVol(condStr, idx))  // ofr.vol
        break;
      if (condStr.nExpireInHoliday == 1 &&
          info.IsExpireInHoliday())  // 不含假期
        break;
      bGood = true;
    } while (0);

    FMTBUF(sType, "%d", condStr.nCFETSQuoteType);
    brokerkey.m_nIndex = idx;
    brokerkey.SetBrokerId(sType);

    if (!bGood) {
      CBrokerKeyVector::iterator itKey = std::find(
          vct_resdel.m_vct.begin(), vct_resdel.m_vct.end(), brokerkey);
      if (itKey == vct_resdel.m_vct.end())  // 去重
        vct_resdel.m_vct.push_back(brokerkey);
    } else {
      CBrokerKeyVector::iterator itKey = std::find(
          vct_result.m_vct.begin(), vct_result.m_vct.end(), brokerkey);
      if (itKey == vct_result.m_vct.end())  // 去重
        vct_result.m_vct.push_back(brokerkey);
    }
    // NETLOG("[LANCETEST] code=%s, price=%s, bGood=%s", info.GetCombBondCode(),
    // itor->m_price, bGood ? "true" : "false"); NETLOG("%s has been pushed -->
    // vct_result, ver = %d", itor->m_bond_shorname, bContinue ? "vct_result" :
    // "vct_resdel", itor->m_version);
  }

  return true;
}

int CBondContainer::GetSize() {
  READLOCK(m_mutex);
  return m_vctbond.size();
}
int CBondContainer::GetSizeImpl() { return m_vctbond.size(); }

const CBondInfo& CBondContainer::ElementAtR(int nIndex) const {
  // NEEDCHECK
  ////SP_ASSERT(nIndex >= 0 && nIndex < (int)m_vctbond.size());
  if (nIndex < 0 || nIndex >= (int)m_vctbond.size()) {
    return m_bond_null;
  }
  USE_BOND(CBondInfo, nIndex);
  return *m_vctbond[nIndex];
}

CBondInfo& CBondContainer::ElementAtW(int nIndex) {
  /*
          之所以引入m_bond_null_write,是因为ElementAtW可能返回m_bond_null
          外界不加判断就改写此CBondInfo,可能导致m_bond_null改变
          以此确保m_bond_null永远不变
  */
  // NEEDCHECK
  ////SP_ASSERT(nIndex >= 0 && nIndex < (int)m_vctbond.size());
  if (nIndex < 0 || nIndex >= (int)m_vctbond.size()) {
    return m_bond_null_write;
  }
  USE_BOND(CBondInfo, nIndex);
  return *m_vctbond[nIndex];
}

CBondCompanyRep* CBondContainer::GetCompanyRep(int nIndex) {
  return BrokerRepMng->GetReport(nIndex);
}

CBondCompanyRep* CBondContainer::GetBrokerMixedBPRep(int nIndex) {
  return BrokerBPRepMng->GetReport(nIndex);
}

CBondBankRep* CBondContainer::GetBankRep(int nIndex) {
  return BankRepMng->GetReport(nIndex);
}

CBondBankRep* CBondContainer::GetClntRep(int nIndex) {
  return BankClientRepMng->GetReport(nIndex);
}

CXCQuoteRep* CBondContainer::GetXCQuote(int nIndex) {
  return XCQuoteRepMng->GetReport(nIndex);
}

CCFETSQuoteRep* CBondContainer::GetCFETSQuote(int nIndex) {
  return CfetsRepMng->GetReport(nIndex);
}

CCFETSDealQuoteRep* CBondContainer::GetCFETSDealQuote(int nIndex) {
  return CfetsDealRepMng->GetReport(nIndex);
}

void CBondContainer::ClearVersion() {
  WRITELOCK(m_mutex);
  m_verarr.clear();
}

void CBondContainer::ClearVersion(int clrFlag) {
  WRITELOCK(m_mutex);
  if (clrFlag == LIQ_CLR_BESTPRICE_ALL) {
    ClearVersion();
  } else {
    std::map<std::string, int>::iterator pos;
    for (pos = m_verarr.begin(); pos != m_verarr.end();) {
      if ((clrFlag == LIQ_CLR_BESTPRICE_BROKE) && (pos->first != "e") &&
          (pos->first != "c")) {
        m_verarr.erase(pos++);
      } else if ((clrFlag == LIQ_CLR_BESTPRICE_CFETS) && (pos->first == "c")) {
        m_verarr.erase(pos++);
      } else if ((clrFlag == LIQ_CLR_BESTPRICE_EXCHANGE) &&
                 (pos->first == "e")) {
        m_verarr.erase(pos++);
      } else {
        ++pos;
      }
    }
  }
}

int CBondContainer::GetVersionById(const std::string& szKey) {
  READLOCK(m_mutex);
  if (m_verarr.size() > 0) {
    std::map<std::string, int>::iterator it = m_verarr.find(szKey);
    if (it != m_verarr.end()) return it->second;
  }
  return 0;
}

void CBondContainer::UpdateVersionById(const std::string& szKey, int nVerNo,
                                       time_t nTime) {
  WRITELOCK(m_mutex);
  m_verarr[szKey] = nVerNo;
  if (nTime <= 0) nTime = ServerTimeMgr::instance().serverTime();
  QDateTime qdt;
  qdt.setTimeSpec(Qt::UTC);  // TODO OK?
  qdt.setSecsSinceEpoch(nTime);
  m_nLastReportDate =
      qdt.date().year() * 10000 + qdt.date().month() * 100 + qdt.date().day();
}

bool CBondContainer::CheckCFETSDayChanged() {
  CReportManagerBase::Scoped l(CfetsRepMng->GetMutex());
  return CfetsRepMng->isDayChanged();
}

void CBondContainer::ClearCFETSDealQuoteVersion() {
  CReportManagerBase::Scoped l(CfetsDealRepMng->GetMutex());
  CfetsDealRepMng->ClearVersion();
}

int CBondContainer::GetCFETSDealQuoteVersion() {
  CReportManagerBase::Scoped l(CfetsDealRepMng->GetMutex());
  return CfetsDealRepMng->GetVersion();
}

bool CBondContainer::CheckCFETSDealDayChanged() {
  CReportManagerBase::Scoped l(CfetsDealRepMng->GetMutex());
  return CfetsDealRepMng->isDayChanged();
}

bool CBondContainer::GetStateType(
    const BLHCONDITION& Cond,
    const CBondInfo& Info) {  //=全部，1=今日簿记建档，2=当日发行，3=当日公告

  bool bRet = false;
  switch (Cond.nStateType) {
    case 1:
      bRet = IsInToday(this, Info.GetAuctionDateStart());
      break;
    case 2:
      bRet = IsInToday(this, Info.GetIssueStartDate());
      break;
    case 3:
      bRet = IsInToday(this, Info.GetAnnounceDate());
      break;
    default:
      break;
  }

  return bRet;
}

bool CBondContainer::GetIssueStartDate(const BLHCONDITION& Cond,
                                       const CBondInfo& Info) {
  const char* pIssueStartDate = Info.GetIssueStartDate();
  if (!IsEmpty(pIssueStartDate)) {
    int nTime = atoi(pIssueStartDate);
    if (nTime >= atoi(Cond.szIssueDateB) && nTime <= atoi(Cond.szIssueDateE))
      return true;
  }
  return false;
}

CBondInfo* CBondContainer::GetBond(const std::string& sBondKey,
                                   const std::string& sMarket) {
  return GetBond(sBondKey + "." + sMarket);
}

CBondInfo* CBondContainer::GetBond(const std::string& sCombBondKey) {
  int bid = GetBondIndexImpl(sCombBondKey.c_str(), sCombBondKey.size());
  return GetBond(bid);
}

CBondInfo* CBondContainer::GetBond(int nBondIndex) {
  if (nBondIndex < 0 || nBondIndex >= (int)m_vctbond.size()) return nullptr;
  return m_vctbond[nBondIndex];
}

int CBondContainer::GetBondIndex(const std::string& sBondKey,
                                 const std::string& sMarket) {
  char keybuf[64] = {0};
  if (sBondKey.size() + 1 + sMarket.size() >= sizeof(keybuf)) return -1;

  int len = FIELDCOPY(keybuf, sBondKey.c_str());
  keybuf[len++] = '.';
  len += FIELDCOPYN(keybuf + len, sizeof(keybuf) - len, sMarket.c_str());
  return GetBondIndexImpl(keybuf, len);
}
int CBondContainer::GetBondIndex(const char* sBondKey, const char* sMarket) {
  char keybuf[64] = {0};
  int len = FIELDCOPY(keybuf, sBondKey);
  if (len + 1 < sizeof(keybuf)) {
    keybuf[len++] = '.';
    len += FIELDCOPYN(keybuf + len, sizeof(keybuf) - len, sMarket);
    return GetBondIndexImpl(keybuf, len);
  }
  return -1;
}
int CBondContainer::GetBondIndex(const std::string& sCombBondKey) {
  return GetBondIndexImpl(sCombBondKey.c_str(), sCombBondKey.size());
}
bool CBondContainer::IsValidIndex(int index) {
  if (index < 0) return false;
  int nsize = GetSizeImpl();
  return index < nsize ? true : false;
}
int CBondContainer::GetBondIndexImpl(const char* sCombBondKey, int len) {
  void* pArrayID = nullptr;
  READLOCK(m_mutex);
  if (m_keymap.Lookup(sCombBondKey, pArrayID)) {
    uint64_t uArrayID = (uint64_t)pArrayID;
    return (int)uArrayID;
  }
  return -1;
}
int CBondContainer::GetBondIndexByCodeImpl(const char* sCombBondCode, int len) {
  void* pArrayID = nullptr;
  READLOCK(m_mutex);
  if (m_map.Lookup(sCombBondCode, pArrayID)) {
    uint64_t uArrayID = (uint64_t)pArrayID;
    return (int)uArrayID;
  }
  return -1;
}
bool CBondContainer::GetFreezeReport(const char* szCompanyID) {
  if (szCompanyID == nullptr) {
    return false;
  }
  return false;
}

bool CBondContainer::RetrieveSupperNewBonds(const BLHCONDITION& condStr,
                                            std::vector<int>& array_result) {
  if (condStr.nBrokId[0] == 0 && IsEmpty(condStr.sCompanyid)) return false;

  HUGELOCK(m_mutex);
  if (condStr.isAllin()) {
    int nSize = GetSize();
    for (int i = 0; i < nSize; i++)  // BIGLOOP
      array_result.push_back(i);
  } else {
    int nCount = 0;
    int nSize = GetSize();
    for (int i = 0; i < nSize; i++)  // BIGLOOP
    {
      bool bContinue = true;
      const CBondInfo& info = ElementAtR(i);

      if (bContinue && condStr.nTypeNew[0] != BondSC_All &&
          !info.ShortCheckBondType(condStr))
        bContinue = false;
      if (bContinue && condStr.nIssuerRating[0] != RatingAll &&
          !GetMultiLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nOutlookRating[0] != OutlookRatingAll &&
          !GetOutlookRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nCDCRating[0] != CDCRatingAll &&
          !GetCDCRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCSIRating[0] != CSIRatingAll &&
          !GetCSIRatingLevel(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCBRRating[0] != CBRRatingAll &&
          !GetCBRRatingLevel(condStr, info))
        bContinue = false;

      if (bContinue && condStr.nDeadLineRange[0] != DL_RangeAll &&
          !GetDeadLineRange(condStr, info))
        bContinue = false;
      if (bContinue && condStr.nCreditBond != 0 &&
          !info.IsSuperNewBond(condStr))
        bContinue = false;
      if (bContinue && !info.IsInDays(condStr)) bContinue = false;
      if (bContinue) {
        array_result.push_back(i);
        nCount++;
      }
    }
  }

  return true;
}

bool CBondContainer::CompareRemainingDay(std::string& sPeriod1,
                                         std::string& sPeriod2) {
  double dDay1 = CBondContainer::CalcRemainingDay(sPeriod1);
  double dDay2 = CBondContainer::CalcRemainingDay(sPeriod2);
  if (dDay1 == dDay2)  // 365D小于1Y小于366D
  {
    bool bStatus1 = sPeriod1.find("Y") != std::string::npos;
    bool bStatus2 = sPeriod2.find("Y") != std::string::npos;
    if (bStatus1 && !bStatus2) {
      return false;
    } else if (!bStatus1 && bStatus2) {
      return true;
    }

    return false;
  }

  return dDay1 < dDay2;
}

bool CBondContainer::GetLatestCompanyRepByBondIndex(int nBondIndex,
                                                    REPORT& stRep,
                                                    bool bBuyPool) {
  if (nBondIndex < 0 || nBondIndex >= GetSize()) return false;
  memset(&stRep, 0, sizeof(REPORT));
  CBondCompanyRep* ptmp = GetCompanyRep(nBondIndex);
  return ptmp ? ptmp->GetLatestReport(stRep, bBuyPool) : false;
}

bool CBondContainer::GetAdditionList(int nID, std::set<int>*& pSet) {
  pSet = nullptr;
  READLOCK(m_mutex);
  if (nID < 0 || nID >= (int)m_vctbond.size()) return false;

  std::map<int, std::set<int>>::iterator it = m_mapaddi.find(nID);
  if (it != m_mapaddi.end()) {
    pSet = &(it->second);
    return true;
  }
  return false;
}

bool CBondContainer::IsHyHasPrice(const BLHCONDITION& Cond, int nID) {
  // TODO
  return false;
}

bool CBondContainer::CheckSettlement(const BLHCONDITION& Cond, int nID) {
  class SettlementChecker : public CBondCompanyRep::ApplyCallback {
    bool m_result;
    const BLHCONDITION& m_cond;

   public:
    SettlementChecker(const BLHCONDITION& cond)
        : m_result(false), m_cond(cond) {}
    bool operator()(CBondCompanyRep* ptmp) {
      m_result = false;
      if (ptmp) ptmp->ApplyAccess(true, "", this);
      return m_result;
    }
    virtual bool DoAccess(const REPORT& rpt) {
      if (CBondContainer::CheckSettlement(m_cond, rpt.m_bidinfo)) {
        m_result = true;
        return false;
      }
      if (CBondContainer::CheckSettlement(m_cond, rpt.m_askinfo)) {
        m_result = true;
        return false;
      }
      return true;  // 表示继续遍历
    }
  };

  if (Cond.nSettlement[0] == StmAll) return true;
  if (Cond.nSettlement[0] == StmNone) return false;

  if (strlen(Cond.sCompanyid) <= 0) {
    CBondCompanyRep* ptmp = GetCompanyRep(nID);
    if (!ptmp) return false;
    SettlementChecker checker(Cond);
    return checker(ptmp);
  } else {
    REPORT stRep = {0};
    if (!GetCompanyRepById(nID, Cond.sCompanyid, stRep)) return false;
    if (CheckSettlement(Cond, stRep.m_bidinfo)) return true;
    if (CheckSettlement(Cond, stRep.m_askinfo)) return true;
    return false;
  }
  return false;
}

bool CBondContainer::CheckSettlement(const BLHCONDITION& Cond,
                                     const PRICE& prc) {
  PRICE_SETTLEMENT_LIST lst;
  DecodeSettlement(prc, lst);
  if (lst.size() <= 0) return false;

  int sz = sizeof(Cond.nSettlement) / sizeof(int);
  for (int i = 0; i < sz; i++) {
    switch (Cond.nSettlement[i]) {
      case StmNone:
        return false;
        break;
      case StmAll:
        return true;
        break;
      case StmT0:
        for (auto& it : lst) {
          if (0 != (it.m_type & 0x1)) {
            return true;
          }
        }
        break;
      case StmT1:
        for (auto& it : lst) {
          if (0 != (it.m_type & 0x2)) {
            return true;
          }
        }
        break;
      case StmFwd:
        for (auto& it : lst) {
          if (0 != (it.m_type & 0x4)) {
            return true;
          }
        }
        break;
      case StmSpot:
        for (auto& it : lst) {
          if (0 != (it.m_type & 0x3)) {
            return true;
          }
        }
        break;
      default:
        break;
    }
  }
  return false;
}

bool CBondContainer::GetVolBidCompare(const BLHCONDITION& Cond, int nID) {
  class GetBidVolCompareCallback : public CBondCompanyRep::ApplyCallback {
    bool m_result;
    int m_nBondIndex;
    const BLHCONDITION& m_cond;

   public:
    GetBidVolCompareCallback(const BLHCONDITION& cond, const int nBondIndex)
        : m_result(false), m_cond(cond), m_nBondIndex(nBondIndex) {}
    bool GetResult() const { return m_result; }
    virtual bool DoAccess(const REPORT& quote)  // true表示可继续,false表示中断
    {
      if (IsEmpty(quote.m_bidinfo.m_sVolume) ||
          strcmp(quote.m_bidinfo.m_sVolume, "--") == 0) {
        // 无效报量
        m_result = false;
      } else {
        double fFilterVol = atof(m_cond.sVolBid);
        std::vector<std::string> vctDest;
        _SplitStr(vctDest, quote.m_bidinfo.m_sVolume, "+");
        for (auto it = vctDest.begin(); it != vctDest.end(); ++it) {
          double fVolumn = atof(it->c_str());
          if (m_cond.nVolBpcCnd == 0)  // 0 表示[<= ], 1 表示[>= ]
          {
            if (fVolumn < fFilterVol + 0.000001) {
              m_result = true;
              return false;
            }
          } else {
            if (fVolumn > fFilterVol - 0.000001) {
              m_result = true;
              return false;
            }
          }
        }
      }
      return m_result ? false : true;
    }
  };

  if (IsEmpty(Cond.sVolBid)) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (!ptmp) return false;

  GetBidVolCompareCallback accessor(Cond, nID);
  ptmp->ApplyAccess(IsEmpty(Cond.sCompanyid), Cond.sCompanyid, &accessor);
  if (accessor.GetResult()) return true;

  return false;
}

bool CBondContainer::GetVolOfrCompare(const BLHCONDITION& Cond, int nID) {
  class GetOfrVolCompareCallback : public CBondCompanyRep::ApplyCallback {
    bool m_result;
    int m_nBondIndex;
    const BLHCONDITION& m_cond;

   public:
    GetOfrVolCompareCallback(const BLHCONDITION& cond, const int nBondIndex)
        : m_result(false), m_cond(cond), m_nBondIndex(nBondIndex) {}
    bool GetResult() const { return m_result; }
    virtual bool DoAccess(const REPORT& quote)  // true表示可继续,false表示中断
    {
      if (IsEmpty(quote.m_askinfo.m_sVolume) ||
          strcmp(quote.m_askinfo.m_sVolume, "--") == 0) {
        // 无效报量
        m_result = false;
      } else {
        double fFilterVol = atof(m_cond.sVolOfr);
        std::vector<std::string> vctDest;
        _SplitStr(vctDest, quote.m_askinfo.m_sVolume, "+");
        for (auto it = vctDest.begin(); it != vctDest.end(); ++it) {
          double fVolumn = atof(it->c_str());
          if (m_cond.nVolOpcCnd == 0)  // 0 表示[<= ], 1 表示[>= ]
          {
            if (fVolumn < fFilterVol + 0.000001) {
              m_result = true;
              return false;
            }
          } else {
            if (fVolumn > fFilterVol - 0.000001) {
              m_result = true;
              return false;
            }
          }
        }
      }
      return m_result ? false : true;
    }
  };

  if (IsEmpty(Cond.sVolOfr)) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (!ptmp) return false;

  GetOfrVolCompareCallback accessor(Cond, nID);
  ptmp->ApplyAccess(IsEmpty(Cond.sCompanyid), Cond.sCompanyid, &accessor);
  if (accessor.GetResult()) return true;

  return false;
}

bool CBondContainer::GetExchangeType(const BLHCONDITION& Cond,
                                     const CBondInfo& Info) {
  int sz = sizeof(Cond.nListedPlace) / sizeof(UINT);
  bool valid = false;
  for (int i = 0; i < sz; i++) {
    switch (Cond.nListedPlace[i]) {
      case kExchAll:
        if (i == 0) return true;
        break;
      case kExchBroker:
        valid |= strcmp(Info.GetListedMarket(), lmCIB) == 0;
        break;
      case kExchSSE:
        valid |= strcmp(Info.GetListedMarket(), lmSSE) == 0;
        break;
      case kExchSZE:
        valid |= strcmp(Info.GetListedMarket(), lmSZE) == 0;
        break;
      case kExchBSE:
        valid |= strcmp(Info.GetListedMarket(), lmBSE) == 0;
        break;
      default:
        break;
    }
  }
  return valid;
}

bool CBondContainer::CheckCDCValuationRange(const BLHCONDITION& Cond, int nID) {
  if (Cond.sCdcValue[0] == '\0' && Cond.sCdcValueEnd[0] == '\0')  // 无范围筛选
    return true;

  CBondInfo* pInfo = CBondContainer::instance().GetBond(nID);
  if (!pInfo || !pInfo->IsCDCAuthValid())  // 无中债权限
    return false;

  int nOptType = CBondCDCPriceInfo::est_type_invalid;
  std::string sCdcValue = CBondCDCPriceInfo::instance().GetCDCPriceYesterday(
      nOptType, true, nID, CBondCDCPriceInfo::price_type_yield, false);
  if (sCdcValue.length() <= 0 || sCdcValue == "--") {  // 无中债估值
    return false;
  }

  if (nOptType == CBondCDCPriceInfo::est_type_invalid) return false;

  double fValue = atof(sCdcValue.c_str());

  if (Cond.sCdcValue[0] != '\0') {
    if (fValue < atof(Cond.sCdcValue) - 1e-6) return false;
  }
  if (Cond.sCdcValueEnd[0] != '\0') {
    if (fValue > atof(Cond.sCdcValueEnd) + 1e-6) return false;
  }
  return true;
}

bool CBondContainer::GetBidCdcCompare(const BLHCONDITION& Cond, int nID) {
  class GetBidCdcCompareCallback : public CBondCompanyRep::ApplyCallback {
    bool m_result;
    int m_nBondIndex;
    bool m_bIsCDCAuthValid;
    const BLHCONDITION& m_cond;

   public:
    GetBidCdcCompareCallback(const BLHCONDITION& cond, const int nBondIndex,
                             bool bIsCDCAuthValid)
        : m_result(false),
          m_cond(cond),
          m_nBondIndex(nBondIndex),
          m_bIsCDCAuthValid(bIsCDCAuthValid) {}
    bool GetResult() const { return m_result; }
    virtual bool DoAccess(const REPORT& quote)  // true表示可继续,false表示中断
    {
      if (IsEmpty(quote.m_bidinfo.m_sPrice) ||
          strcmp(quote.m_bidinfo.m_sPrice, "Bid") == 0 ||
          strcmp(quote.m_bidinfo.m_price_status, "0") ==
              0 /*||strcmp(info.GetEstPrice(),"0")==0*/
          || (!IsEmpty(quote.m_bidinfo.m_quotetype) &&
              atoi(quote.m_bidinfo.m_quotetype) == 0))  // 有意向
      {
        // 无效价格，或者无效估值
        m_result = false;
      } else {
        if (quote.m_bidinfo.m_yield_price[0] == '\0') {
          m_result = false;
          return true;
        }
        double fYield = atof(quote.m_bidinfo.m_yield_price);
        if (quote.m_company_id[0] != 'e' &&
            atoi(quote.m_bidinfo.m_quotetype) != 3) {
          CBondInfo* pInfo = CBondContainer::instance().GetBond(m_nBondIndex);
          if (pInfo && (pInfo->IsBondABS() || pInfo->IsTransBond())) {
            if (fYield <= 0 || fYield >= 30) {
              m_result = false;
              return true;
            }
          }
        }

        double dDiff = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
            m_bIsCDCAuthValid, m_nBondIndex,
            CBondCDCPriceInfo::price_type_yield, true,
            quote.m_bidinfo.m_yield_price, INVALID_CDC_VALUE, false);
        if (dDiff < INVALID_CDC_VALUE + 1e-6) {
          m_result = false;
          return true;
        }
        m_result = true;
        if (m_cond.sBidCdc[0] != 0) {
          if (dDiff < atof(m_cond.sBidCdc) - 1e-6) {
            m_result = false;
            return true;
          }
        }
        if (m_cond.sBidCdcEnd[0] != 0) {
          if (dDiff > atof(m_cond.sBidCdcEnd) + 1e-6) {
            m_result = false;
            return true;
          }
        }
      }
      return m_result ? false : true;
    }
  };

  if (IsEmpty(Cond.sBidCdc)) return true;

  int nOptType = CBondCDCPriceInfo::est_type_invalid;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp) {
    bool bIsCDCAuthValid = true;
    CBondInfo* pInfo = nullptr;
    pInfo = GetBond(nID);
    if (pInfo->IsCDCAuthValid()) {
      bIsCDCAuthValid = pInfo->IsCDCAuthValid();
    }
    GetBidCdcCompareCallback accessor(Cond, nID, bIsCDCAuthValid);
    ptmp->ApplyAccess(IsEmpty(Cond.sCompanyid), Cond.sCompanyid, &accessor);
    if (accessor.GetResult()) return true;
  }
  return false;
}

bool CBondContainer::GetCdcOfrCompare(const BLHCONDITION& Cond, int nID) {
  if (IsEmpty(Cond.sCdcOfr)) return true;

  CBondCompanyRep* ptmp = GetCompanyRep(nID);
  if (ptmp && ptmp->GetSize() > 0) {
    class GetCdcOfrCompareCallback : public CBondCompanyRep::ApplyCallback {
      bool m_result;
      int m_nBondIndex;
      bool m_bIsCDCAuthValid;
      const BLHCONDITION& m_cond;

     public:
      GetCdcOfrCompareCallback(const BLHCONDITION& cond, int nId,
                               bool bIsCDCAuthValid)
          : m_result(false),
            m_cond(cond),
            m_nBondIndex(nId),
            m_bIsCDCAuthValid(bIsCDCAuthValid) {}
      bool GetResult() const { return m_result; }
      virtual bool DoAccess(
          const REPORT& quote)  // true表示可继续,false表示中断
      {
        if (IsEmpty(quote.m_askinfo.m_sPrice) ||
            strcmp(quote.m_askinfo.m_sPrice, "Ofr") == 0 ||
            strcmp(quote.m_askinfo.m_price_status, "0") ==
                0 /*||strcmp(info.GetEstPrice(),"0")==0*/) {
          // 无效价格，或者无效估值
          m_result = false;
        } else {
          if (quote.m_askinfo.m_yield_price[0] == '\0') {
            m_result = false;
            return true;
          }
          double fYield = atof(quote.m_askinfo.m_yield_price);
          if (atoi(quote.m_askinfo.m_quotetype) != 3) {
            CBondInfo* pInfo = CBondContainer::instance().GetBond(m_nBondIndex);
            if (pInfo && (pInfo->IsBondABS() || pInfo->IsTransBond())) {
              if (fYield <= 0 || fYield >= 30) return false;
            }
          }

          double dDiff = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
              m_bIsCDCAuthValid, m_nBondIndex,
              CBondCDCPriceInfo::price_type_yield, false,
              quote.m_askinfo.m_yield_price, INVALID_CDC_VALUE, false);
          if (dDiff < INVALID_CDC_VALUE + 1e-6) {
            m_result = false;
            return true;
          }
          if (m_cond.sCdcOfr[0] != 0) {
            if (dDiff < atof(m_cond.sCdcOfr) - 1e-6) {
              m_result = false;
              return true;
            }
          }
          if (m_cond.sCdcOfrEnd[0] != 0) {
            if (dDiff > atof(m_cond.sCdcOfrEnd) + 1e-6) {
              m_result = false;
              return true;
            }
          }
          m_result = true;
        }
        return m_result ? false : true;
      }
    };
    bool bIsCDCAuthValid = true;
    CBondInfo* pInfo = nullptr;
    pInfo = GetBond(nID);
    if (pInfo->IsCDCAuthValid()) {
      bIsCDCAuthValid = pInfo->IsCDCAuthValid();
    }
    GetCdcOfrCompareCallback accessor(Cond, nID, bIsCDCAuthValid);
    ptmp->ApplyAccess(IsEmpty(Cond.sCompanyid), Cond.sCompanyid, &accessor);
    if (accessor.GetResult()) return true;
  }
  return false;
}

bool CBondContainer::CheckMarketMakeTargetType(const BLHCONDITION& Cond,
                                               const CBondInfo& Info) {
  int sz = sizeof(Cond.nMarketMakeTarget) / sizeof(UINT);
  string szCombBondCode = Info.GetCombBondCode();
  for (int i = 0; i < sz; i++) {
    if (Cond.nMarketMakeTarget[i] == 0x00) continue;

    bool bTarget = CMarketMakeTarget::instance().IsMarkertMakeTarget(
        Cond.nMarketMakeTarget[i], szCombBondCode);
    switch (Cond.nMarketMakeTarget[i]) {
      case eMarketMakeTarget::kMarketSSEInterest:
        if (bTarget) {
          return true;
        }
        break;
      case eMarketMakeTarget::kMarketSSECredit:
        if (bTarget) {
          return true;
        }
        break;
      case eMarketMakeTarget::kMarketSZEInterest:
        if (bTarget) {
          return true;
        }
        break;
      case eMarketMakeTarget::kMarketSZECredit:
        if (bTarget) {
          return true;
        }
        break;
      default:
        break;
    }
  }
  return false;
}

bool CBondContainer::CheckHotType(const BLHCONDITION& Cond,
                                  const CBondInfo& Info) {
  int sz = sizeof(Cond.nPopular) / sizeof(UINT);
  string szCombBondCode = Info.GetCombBondCode();
  for (int i = 0; i < sz; i++) {
    if (Cond.nPopular[i] == 0x00) continue;

    bool bTarget = CMarketMakeTarget::instance().IsMarkertMakeTarget(
        Cond.nPopular[i], szCombBondCode);
    switch (Cond.nPopular[i]) {
      case CBondContainer::HotAll:
        return true;
        break;
      case CBondContainer::HotBankTier2: {
        if (Info.IsBondBankSecond()) return true;
      } break;
      case CBondContainer::HotBankETS: {
        if (Info.IsBondBankPerpetual()) return true;
      } break;
      case CBondContainer::HotPolicyBankTier2: {
        if (Info.IsPolicyBankSecond()) return true;
      } break;
      case CBondContainer::HotInsuranceTier2: {
        if (Info.IsBondInsurance() && Info.IsBondSceniority()) return true;
      } break;
      case CBondContainer::HotPledge: {
        if (Info.IsMortgage()) return true;
      } break;
      case CBondContainer::HotCrossMarket: {
        if (Info.IsCrossMarket()) return true;
      } break;
      case CBondContainer::HotMunicipal: {
        if (Info.IsMunicipal()) return true;
      } break;
      case CBondContainer::HotRealEstate: {
        if (Info.CheckCommonUseType(CBondContainer::CommRealty)) return true;
      } break;
      case CBondContainer::HotOverCapacity: {
        if (Info.CheckCommonUseType(CBondContainer::CommCoal) ||
            Info.CheckCommonUseType(CBondContainer::CommSteel) ||
            Info.CheckCommonUseType(CBondContainer::CommCement))
          return true;
      } break;
      case CBondContainer::HotCoal: {
        if (Info.CheckCommonUseType(CBondContainer::CommCoal)) return true;
      } break;
      case CBondContainer::HotSteel: {
        if (Info.CheckCommonUseType(CBondContainer::CommSteel)) return true;
      } break;
      case CBondContainer::HotCement: {
        if (Info.CheckCommonUseType(CBondContainer::CommCement)) return true;
      } break;
      case CBondContainer::HotPublicUtilities: {
        if (Info.CheckCommonUseType(CBondContainer::CommElect) ||
            Info.CheckCommonUseType(CBondContainer::CommTraffic))
          return true;
      } break;
      case CBondContainer::HotElectricPower: {
        if (Info.CheckCommonUseType(CBondContainer::CommElect)) return true;
      } break;
      case CBondContainer::HotTransportation: {
        if (Info.CheckCommonUseType(CBondContainer::CommTraffic)) return true;
      } break;
      case CBondContainer::HotListedCompany: {
        if (Info.CheckCommonUseType(CBondContainer::CommListedCompany))
          return true;
      } break;
      case CBondContainer::HotESG: {
        for (int index = SectorBond::sector_green;
             index <= SectorBond::sector_sustanable; ++index) {
          if (SectorBond::instance().IsInSector(index, Info.GetCombBondCode()))
            return true;
        }
      } break;
      case CBondContainer::HotGreenBond: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_green,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotSociety: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_society,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotSustanable: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_sustanable,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotMicroBusiness: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_small_corp,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotTechnologyInnovation: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_innoation_corp,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotDefaulted: {
        std::vector<std::string> labelIDs =
            BondSpecialLabelMgr::instance().getLabelIDs(Info.GetCombBondKey());
        if (std::find(labelIDs.begin(), labelIDs.end(), "005") !=
            labelIDs.end())
          return true;
      } break;
      case CBondContainer::HotPanda: {
        if (SectorBond::instance().IsInSector(SectorBond::sector_panda,
                                              Info.GetCombBondCode()))
          return true;
      } break;
      case CBondContainer::HotTLAC: {
        if (Info.IsBondTLAC()) return true;
      } break;
      case CBondContainer::HotNewIssues: {
        if (Info.IsNewBond()) return true;
      } break;
      case CBondContainer::HotExpireInHoliday: {
        if (!Info.IsExpireInHoliday()) return true;
      } break;
      default:
        break;
    }
  }
  return false;
}

bool CBondContainer::GetMaturityRangeEx(const BLHCONDITION& Cond,
                                        const CBondInfo& Info) {
  // NEEDCHECK
  //  GetRemainPeriod 是必须对info进行更改,且有安全风险
  bool bRes = false;
  int nSize = sizeof(Cond.nRange) / sizeof(uint32_t);
  for (int i = 0; i < nSize; i++) {
    switch (Cond.nRange[i]) {
      case DL_RangeDate:
        if (IsEmpty(Cond.sDate1) && IsEmpty(Cond.sDate2)) return true;
        break;
      default:
        break;
    }
  }
  if (IsEmpty(Info.GetMaturityDate())) {
    // LOGWARN("GetMaturityDate is empty");
    return false;
  }

  time_t t = ServerTimeMgr::instance().serverTime();
  std::string str = Info.GetRemainPeriod(t);
  long ldays = (LONG)CalcRemainingDay(str);
  double fYear = ldays / 365.0;

  double lfStartDLYear = 0.0;
  double lfEndDLYear = 0.0;
  // 判断条件：前开后闭
  for (int i = 0; i < nSize; i++) {
    if (Cond.nRange[i] == 0x00) return false;

    switch (Cond.nRange[i]) {
      case DL_Range1: {
        lfStartDLYear = (1 - 1) / 12.0;
        lfEndDLYear = (1 + 1) / 12.0;
      } break;
      case DL_Range2: {
        lfStartDLYear = (3 - 1) / 12.0;
        lfEndDLYear = (3 + 1) / 12.0;
      } break;
      case DL_Range3: {
        lfStartDLYear = (6 - 1) / 12.0;
        lfEndDLYear = (6 + 1) / 12.0;
      } break;
      case DL_Range4: {
        lfStartDLYear = (9 - 2) / 12.0;
        lfEndDLYear = (9 + 2) / 12.0;
      } break;
      case DL_Range5: {
        lfStartDLYear = 1 - 2.0 / 12.0;
        lfEndDLYear = 1 + 2.0 / 12.0;
      } break;
      case DL_Range6: {
        lfStartDLYear = 3 - 2.0 / 12.0;
        lfEndDLYear = 3 + 2.0 / 12.0;
      } break;
      case DL_Range7: {
        lfStartDLYear = 5 - 3.0 / 12.0;
        lfEndDLYear = 5 + 3.0 / 12.0;
      } break;
      case DL_Range8: {
        lfStartDLYear = 7 - 4.0 / 12.0;
        lfEndDLYear = 7 + 4.0 / 12.0;
      } break;
      case DL_Range9: {
        lfStartDLYear = 10 - 4.0 / 12.0;
        lfEndDLYear = 10 + 4.0 / 12.0;
      } break;
      case DL_Range10: {
        lfStartDLYear = 9.5;
        lfEndDLYear = 10000.0;
      } break;
      case DL_RangeDate: {
        lfStartDLYear = atof(Cond.sDate1);
        lfEndDLYear = atof(Cond.sDate2);
      } break;
      case DL_Range21: {
        lfStartDLYear = 1.00001;
        lfEndDLYear = 10000.0;
      } break;
      default:
        break;
    }

    if (fYear <= lfEndDLYear && fYear > lfStartDLYear)
      return true;
    else
      continue;
  }

  return bRes;
}

bool CBondContainer::CheckVersion() {  // 检查报价版本号，如果跨天，清数据
  QDateTime t =
      QDateTime::fromSecsSinceEpoch(ServerTimeMgr::instance().serverTime());
  int serverDate =
      t.date().year() * 10000 + t.date().month() * 100 + t.date().day();
  if (m_nLastReportDate != serverDate) {
    ClearReport();
    return true;
  }
  return false;
}

bool CBondContainer::CheckBondCdcValid(const char* szBondKey,
                                       const char* szListedMarket) {
  int nID = GetBondIndex(szBondKey, szListedMarket);
  if (nID < 0 || nID >= GetSize()) return false;

  const CBondInfo& info = ElementAtR(nID);
  return info.IsCDCAuthValid();
}

bool CBondContainer::CheckBondCdcValid(const char* szCombBondKey) {
  int nID = GetBondIndex(szCombBondKey);
  if (nID < 0 || nID >= GetSize()) return false;

  const CBondInfo& info = ElementAtR(nID);
  return info.IsCDCAuthValid();
}

void CBondContainer::DumpStatus(int mode) const {}

void CBondContainer::DecodeSettlement(const PRICE& price,
                                      PRICE_SETTLEMENT_LIST& pdList) {
  if (price.m_id[0] == '\0') return;
  //	BASSERT(price.m_interpret[0] != '\0');
  DecodeSettlement(price.m_interpret, pdList);
}

#ifndef WIN32
#define strncpy_s strncpy
#endif
void _decode_interpret(price_settlement& unit, const char*& P,
                       const char*& lastP, int& step) {
  switch (step) {
    case 0:  // 量
      // BASSERTS(P - lastP < 16, "DecodeError");
      if (P != lastP) strncpy_s(unit.m_vol, lastP, P - lastP);
      P++;
      lastP = P;
      step++;
      break;
    case 1:  // 原始备注
      // BASSERTS(P - lastP < 64, "DecodeError");
      if (P != lastP) strncpy_s(unit.m_desc, lastP, P - lastP);
      P++;
      lastP = P;
      step++;
      break;
    case 2:  // 清算速度old
      ////BASSERTS(P - lastP == 1, "DecodeError");
      if (P != lastP) unit.m_typeold = *lastP;
      P++;
      lastP = P;
      step++;
      break;
    case 3:  // 需请示，必须请示
      ////BASSERTS(P - lastP == 1, "DecodeError");
      if (P != lastP) unit.m_bargin = *lastP;
      P++;
      lastP = P;
      step++;
      break;
    case 4:  // 清算速度
      ////BASSERTS(P - lastP == 1, "DecodeError");
      if (P != lastP && *lastP > '0') unit.m_type = *lastP - '0';
      P++;
      lastP = P;
      step++;
      break;
    case 5:  // 部分成交
      if (P != lastP) unit.m_pstar = *lastP;
      P++;
      lastP = P;
      step++;
      break;
    default:  // 向后兼容
      P++;
      lastP = P;
      step++;
      break;
  }
}

void _insertlist_interpret(PRICE_SETTLEMENT_LIST& lst, price_settlement& unit) {
  if (unit.m_type == 0x0 && unit.m_typeold != '\0') {
    if (unit.m_typeold == '0')
      unit.m_type = 0x1;
    else if (unit.m_typeold == '1')
      unit.m_type = 0x2;
    else if (unit.m_typeold == '2')
      unit.m_type = 0x4;
  }

  lst.push_back(unit);
}

void CBondContainer::DecodeSettlement(const char* intp,
                                      PRICE_SETTLEMENT_LIST& pdList) {
  if (intp == nullptr || intp[0] == '\0') return;

  const char* P = intp;
  int pos = 0;
  int sz = strlen(intp) + 1;  //'\0'

  int step = 0;
  const char* lastP = P;
  const char* fromP = P;
  price_settlement unit;
  while (pos < sz) {
    if (*P == ',') {
      _decode_interpret(unit, P, lastP, step);
    } else if (*P == ';') {
      _decode_interpret(unit, P, lastP, step);
      strncpy_s(unit.m_original, fromP, P - fromP - 1);
      _insertlist_interpret(pdList, unit);
      fromP = P;
      memset(&unit, 0, sizeof(unit));
      step = 0;
      fromP = P;
    } else if (*P == '\0') {
      _decode_interpret(unit, P, lastP, step);
      strncpy_s(unit.m_original, fromP, P - fromP - 1);
      _insertlist_interpret(pdList, unit);
      fromP = P;
      break;
    } else {
      P++;
    }
    pos++;
  }
}

bool CBondContainer::CheckPrincipalPayType(const BLHCONDITION& Cond,
                                           const CBondInfo& Info) {
  if (Cond.nPrincipalPayType[0] == PPTNone) {
    return false;
  }
  if (Cond.nPrincipalPayType[0] == PPTAll) {
    return Info.IsAmortizing() || Info.IsNonAmortizing();
  }

  int sz = sizeof(Cond.nPrincipalPayType) / sizeof(int);
  for (int i = 0; i < sz; i++) {
    switch (Cond.nPrincipalPayType[i]) {
      case PPTAmortizing:
        if (Info.IsAmortizing()) {
          return true;
        }
        break;
      case PPTNonAmortizing:
        if (Info.IsNonAmortizing()) {
          return true;
        }
        break;
      default:
        break;
    }
  }
  return false;
}

bool CBondContainer::IsSubAbs(const CBondInfo& info) {
  if (info.IsBondABS()) {  // 次级ABS
    int bondIndex = instance().GetBondIndex(info.GetCombBondKey());
    const CABSBondInfo* absinfo = instance().GetABSBondInfo(bondIndex);
    if (absinfo && absinfo->GetTrancheClass() == CABSBondInfo::TRANCHE_SUB)
      return true;
  }
  return false;
}

bool CBondContainer::IsShowFullPrice(const CBondInfo& info) {
  if (info.IsCVBBond()) return true;  // 可转债
  if (IsSubAbs(info)) return true;
  if (strcmp(info.GetListedMarket(), CBondContainer::lmSSE) == 0 ||
      strcmp(info.GetListedMarket(), CBondContainer::lmSZE) == 0 ||
      strcmp(info.GetListedMarket(), CBondContainer::lmBSE) ==
          0) {  // 特定债，Listed Market=SSE|SZE & 债券简称以"H"开头
    const char* shortName = info.GetBondShortName();
    if (shortName && shortName[0] == 'H') return true;
  }
  return false;
}

bool UpdateBondInfoByCFETSQUOTE(CCFETSQuoteRep* pRep,
                                CCFETSQuote::CFETSQUOTETYPE nType,
                                const CFETSQUOTE* pQuote) {
  if (!pQuote) return false;

  return pRep->InsertQuote(nType, *pQuote);
}

bool UpdateBondContainerByCFETSQUOTE(CBondContainer& container,
                                     CCFETSQuote::CFETSQUOTETYPE nType,
                                     const CFETSQUOTE* pQuote) {
  if (nullptr == pQuote) return false;

  int id = 0;
  if (container.GetBondInfoByKey(pQuote->m_sBondKey, pQuote->m_sListedMarket,
                                 nullptr, &id)) {
    CSSReportManager<CCFETSQuoteRep>* pManager = CfetsRepMng;
    if (pManager) {
      CReportManagerBase::Scoped l(pManager->GetMutex());
      CCFETSQuoteRep* prep = pManager->GetReportOrAdd(id);
      if (prep) {
        UpdateBondInfoByCFETSQUOTE(prep, nType, pQuote);
      }
      CfetsRepMng->UpdateVersion((int)nType,
                                 strcmp(pQuote->m_Symbol, "1") == 0
                                     ? pQuote->m_bidversion
                                     : pQuote->m_ofrversion,
                                 pQuote->m_time);
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool UpdateBondContainerByXCQUOTEImpl(CBondContainer& container,
                                      XCQUOTE* pQuote, bool bAddIfNotExist,
                                      XCQUOTE* pLast, int local) {
  if (NULL == pQuote) return false;

  int id = 0;
  if (container.GetBondInfoByKey(pQuote->m_sBondKey, pQuote->m_sListedMarket,
                                 NULL, &id)) {
    CSSReportManager<CXCQuoteRep>* reports = XCQuoteRepMng;
    if (reports) {
      CReportManagerBase::Scoped lock(reports->GetMutex());
      CXCQuoteRep* prep = reports->GetReportOrAdd(id);
      if (prep) prep->InsertQuote(*pQuote);
    } else {
      log_error("[BONDLIB]invalid XCQuoteRepMng pointer");
    }
  }
  return true;
}

bool UpdateBondContainerByXCQUOTE(CBondContainer& container, XCQUOTE* pQuote,
                                  bool bAddIfNotExist, XCQUOTE* pLast,
                                  int local) {
  return UpdateBondContainerByXCQUOTEImpl(container, pQuote, bAddIfNotExist,
                                          pLast, local);
}
